您的位置:首页 > 职场人生

黑马程序员——JavaIO流

2015-07-17 20:01 1101 查看
-------android培训java培训、期待与您交流!
----------

一、File类

File是文件和目录(文件夹)路径名的抽象表示形式实现IO的操作,就必须知道硬盘上文件的表现形式。
而Java就提供了一个类File供我们使用。
1:构造方法:

File(String pathname):根据一个路径得到File对象

File(String parent, String child):根据一个目录和一个子文件/目录得到File对象

File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

2:功能

(1)创建功能

public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了

public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了

public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来

(2)删除功能

public boolean delete()

注意事项:

A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。

B:Java中的删除不走回收站。

C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹

(3)重命名功能

public boolean renameTo(File dest)

如果路径名相同,就是改名。

如果路径名不同,就是改名并剪切。

(4)判断功能

public boolean isDirectory():判断是否是目录

public boolean isFile():判断是否是文件

public boolean exists():判断是否存在

public boolean canRead():判断是否可读

public boolean canWrite():判断是否可写

public boolean isHidden():判断是否隐藏

(5)获取功能

public String getAbsolutePath():获取绝对路径

public String getPath():获取相对路径

public String getName():获取名称

public long length():获取长度。字节数

public long lastModified():获取最后一次的修改时间,毫秒值

(6)高级获取功能

public
String[] list():获取指定目录下的所有文件或者文件夹的名称数组

public
File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组

(7)过滤器功能

public String[] list(FilenameFilter filter)

public File[] listFiles(FilenameFilter filter)

3:实例

把E:\评书\三国演义\三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi

改为:E:\评书\三国演义\001_桃园三结义.avi

思路:

A:封装目录

B:获取该目录下所有的文件的File数组

C:遍历该File数组,得到每一个File对象

D:拼接一个新的名称,然后重命名即可。

public static void main(String[] args) {
// 封装目录
File srcFolder = new File("E:\\评书\\三国演义");
// 获取该目录下所有的文件的File数组
File[] fileArray = srcFolder.listFiles();
// 遍历该File数组,得到每一个File对象
for (File file : fileArray) {
// E:\评书\三国演义\三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi
// 改后:E:\评书\三国演义\001_桃园三结义.avi
String name = file.getName(); // 三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi

int index = name.indexOf("_");
String numberString = name.substring(index + 1, index + 4);

int endIndex = name.lastIndexOf('_');
String nameString = name.substring(endIndex);

String newName = numberString.concat(nameString); // 001_桃园三结义.avi

File newFile = new File(srcFolder, newName); // E:\\评书\\三国演义\\001_桃园三结义.avi

// 重命名即可
file.renameTo(newFile);
}
}

二、递归

方法定义中调用方法本身的现象。

1:递归注意事项

a: 要有出口,否则就是死递归
b: 次数不能太多,否则就内存溢出
c: 构造方法不能递归使用
d: 方法的嵌套调用,这不是递归。Math.max(Math.max(a,b),c);

2:递归解决问题的思想

a: 找出出口

b: 找到规律

3:案例

需求:递归删除带内容的目录

思路

A:封装目录

B:获取该目录下的所有文件或者文件夹的File数组

C:遍历该File数组,得到每一个File对象

D:判断该File对象是否是文件夹

是:回到B

否:就删除

public static void main(String[] args) {
// 封装目录
File srcFolder = new File("demo");
// 递归实现
deleteFolder(srcFolder);
}
private static void deleteFolder(File srcFolder) {
// 获取该目录下的所有文件或者文件夹的File数组
File[] fileArray = srcFolder.listFiles();

if (fileArray != null) {
// 遍历该File数组,得到每一个File对象
for (File file : fileArray) {
// 判断该File对象是否是文件夹
if (file.isDirectory()) {
deleteFolder(file);
} else {
System.out.println(file.getName() + "---" + file.delete());
}
}

System.out.println(srcFolder.getName() + "---" + srcFolder.delete());
}
}

三、IO流常用基类

IO流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中。

输入流和输出流相对于内存设备而言的,以程序的角度:

将外设中的数据读取到内存中:输入。

将内存中的数据写入到外设中:输出。

1:IO流的分类

按照数据流向

输入流  读入数据

输出流  写出数据  

按照数据类型

字节流                                      抽象基类 

字节输入流    读取数据    InputStream

字节输出流    写出数据    OutputStream

字符流

字符输入流    读取数据    Reader

字符输出流    写出数据    Writer 

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。

如OutputStream 的子类FileOutputStream

2:字节流

字节流主要是操作byte(字节)的类型数据

(1)FileOutputStream

A: 构造方法

FileOutputStream(File file)

FileOutputStream(String name)

B:字节流写数据的方法

public void write(int b): 写一个字节

public void write(byte[] b): 写一个字节数组

public void write(byte[] b, int off, int len): 写一个字节数组的一部分

\r\n:换行符

追加数据写入:用构造方法带第二个参数是true的情况即可。

FileOutputStream fos = null;//创建对象
try {
fos = new FileOutputStream("fos.txt");//存储文件
fos.write("java".getBytes());//写入数据
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果fos不是null,才需要close()
if (fos != null) {
// 为了保证close()一定会执行,就放到这里了
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


(2)FileInputStream

A: 构造方法

FileInputStream(File file)

FileInputStream(String name)

B: 字节流读取数据的方法

public int read(): 一次读取一个字节

public int read(byte[] b): 一次读取一个字节数组。返回值其实是实际读取的字节个数

public static void main(String[] args) throws IOException {
// 创建字节输入流对象
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");
// 读取数据
// 定义一个字节数组
// 数组的长度一般是1024或者1024的整数倍
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {// 如果读取到的实际长度是-1,就说明没有数据了
System.out.print(new String(bys, 0, len));
}
// 释放资源
fis.close();
}


(3)复制文件

需求:把c盘下的a.txt的内容复制到d盘下的b.txt中

数据源:

c:\\a.txt--读取数据--FileInputStream

目的地:

d:\\b.txt--写出数据--
FileOutputStream

public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("c:\\a.mp4");
// 封装目的地
FileOutputStream fos = new FileOutputStream("d:\\b.mp4");

// 复制数据
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}

// 释放资源
fos.close();
fis.close();
}

(4)字节缓冲区

缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率。

字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。

写数据:BufferedOutputStream

读数据:BufferedInputStream

public static void method1(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}

fos.close();
fis.close();
}

3:字符转换流

由于字节流操作中文不是特别方便,所以,java就提供了转换流。是字节与字符之间的桥梁。转换流其实是一个字符流

字符流=字节流+编码表。

(1)构造

OutputStreamWriter 字符输出流

public OutputStreamWriter(OutputStream out): 根据默认编码把字节流的数据转换为字符流

public OutputStreamWriter(OutputStream out,String charsetName): 根据指定编码把字节流数据转换为字符流

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"), "UTF-8"); // 指定UTF-8


InputStreamReader 字符输入流

public InputStreamReader(InputStream in): 用默认的编码读取数据

public InputStreamReader(InputStream in,String charsetName): 用指定的编码读取数据

InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"), "UTF-8");


(2)方法

OutputStreamWriter写数据方法

public void write(int c): 写一个字符

public void write(char[] cbuf): 写一个字符数组

public void write(char[] cbuf,int off,int len): 写一个字符数组的一部分

public void write(String str): 写一个字符串

public void write(String str,int off,int len): 写一个字符串的一部分

flush():刷新缓冲区

close()和flush()的区别?

A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。

B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。

IntputStreamReader读数据方法

public int read(): 一次读取一个字符

public int read(char[] cbuf): 一次读取一个字符数组

(3)子类

OutputStreamWriter = FileOutputStream + 编码表

|—FileWriter = FileOutputStream + 编码表

InputStreamReader = FileInputStream + 编码表

|—FileReader = FileInputStream + 编码表

(4)字符缓冲区

a: 对应类

BufferedWriter: 字符缓冲输出流

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

b: 字符缓冲流的特殊方法

public void newLine(): 根据系统来决定换行符

public String readLine(): 一次读取一行数据。包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

原理:使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记,将标记前的缓冲数据变成字符串返回。

public static void main(String[] args) throws IOException {
// 封装数据源
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

// 读写数据
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}

// 释放资源
bw.close();
br.close();
}


c: 跟踪行号的缓冲字符输入流

LineNumberReader: 此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。

四、IO包中其他流

1:数据操作流

可以操作基本类型的数据

数据输入流:DataInputStream

DataInputStream(InputStream in)

数据输出流:DataOutputStream

DataOutputStream(OutputStream out) 

private static void read() throws IOException {
// DataInputStream(InputStream in)
// 创建数据输入流对象
DataInputStream dis = new DataInputStream(
new FileInputStream("dos.txt"));

// 读数据
byte b = dis.readByte();
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
char c = dis.readChar();
boolean bb = dis.readBoolean();

// 释放资源
dis.close();

System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(c);
System.out.println(bb);
}
private static void write() throws IOException {
// DataOutputStream(OutputStream out)
// 创建数据输出流对象
DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));

// 写数据了
dos.writeByte(10);
dos.writeShort(100);
dos.writeInt(1000);
dos.writeLong(10000L);
dos.writeFloat(12.34F);
dos.writeDouble(12.56);
dos.writeChar('a');
dos.writeBoolean(true);

// 释放资源
dos.close();
}
2:内存操作流

之前的文件操作流是以文件的输入输出为主的,当输出的位置变成了内存,那么就称为内存操作流。

用于处理临时存储信息的,程序结束,数据就从内存中消失。

操作字节数组

ByteArrayInputStream将内容写到内存中

ByteArrayOutputStream   将内存中的数据写出

操作字符数组

CharArrayReader

CharArrayWrite

操作字符串

StringReader

StringWriter

public static void main(String[] args) throws IOException {
// 写数据
ByteArrayOutputStream baos = new ByteArrayOutputStream();

// 写数据
for (int x = 0; x < 10; x++) {
baos.write(("hello" + x).getBytes());
}
// 释放资源
// 通过查看源码知道这里什么都没做,所以根本需要close()
// baos.close();

byte[] bys = baos.toByteArray();//得到真正的数据

// 读数据
// ByteArrayInputStream(byte[] buf)
ByteArrayInputStream bais = new ByteArrayInputStream(bys);

int by = 0;
while ((by = bais.read()) != -1) {
System.out.print((char) by);
}
}

3:打印流

字节流打印流      PrintStream

字符打印流          PrintWriter

特点:

A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。

B:可以操作任意类型的数据。

C:如果启动了自动刷新,能够自动刷新。

D:该流是可以直接操作文本文件的。

构造:

public PrintStream(File file) throws FileNotFoundException

public PrintStream(OutputStream out)

PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

还是应该调用println()的方法才可以

这个时候不仅仅自动刷新了,还实现了数据的换行。

4:标准输入输出流

System类中的两个成员变量:

public static final InputStream in “标准”输入流。

public static final PrintStream out “标准”输出流。

InputStream is = System.in;

PrintStream ps = System.out;

(1)键盘录入数据

A:main方法的args接收参数。

java HelloWorld 

B:Scanner(JDK5以后的)

Scanner sc = new Scanner(System.in);

String s = sc.nextLine();

int x = sc.nextInt()

C:通过字符缓冲流包装标准输入流实现

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

(2)获取标准输入流

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write("hello");
bw.write("world");
bw.write("java");

bw.newLine();
bw.flush();
bw.close();


5:随机访问流

RandomAccessFile类不属于流,是Object类的子类。

但它融合了InputStream和OutputStream的功能。

支持对随机访问文件的读取和写入。

方法:

public RandomAccessFile(String name,String mode):第一个参数是文件路径,第二个参数是操作文件的模式。

模式有四种,我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据 

6:合并流

SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。

构造方法

SequenceInputStream(InputStream s1, InputStream s2)  

SequenceInputStream(Enumeration<? extends InputStream> e)

把多个文件的内容写入到一个文本文件

需求:把a.txt, b.txt, c.txt复制到d.txt

public static void main(String[] args) throws IOException {
// SequenceInputStream(Enumeration e)
// Enumeration是Vector中的一个方法的返回值类型。
// Enumeration<E> elements()
Vector<InputStream> v = new Vector<InputStream>();
InputStream s1 = new FileInputStream("a.txt");
InputStream s2 = new FileInputStream("b.txt");
InputStream s3 = new FileInputStream("c.txt");
v.add(s1);
v.add(s2);
v.add(s3);
Enumeration<InputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d.txt"));

// 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
byte[] bys = new byte[1024];
int len = 0;
while ((len = sis.read(bys)) != -1) {
bos.write(bys, 0, len);
}

bos.close();
sis.close();
}

7:序列化流

序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。

对象 -- 流数据(ObjectOutputStream)

反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。

流数据 -- 对象(ObjectInputStream)

被操作的对象需要实现Serializable。
类通过实现java.io.Serializable接口以启用序列化功能,Serializable只是一个标记接口。

用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本。

private static void read() throws IOException, ClassNotFoundException {
// 创建反序列化对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
// 还原对象
Object obj = ois.readObject();
// 释放资源
ois.close();
// 输出对象
System.out.println(obj);
}

private static void write() throws IOException {
// 创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
// 创建对象
Person p = new Person("Donald", 27);
// public final void writeObject(Object obj)
oos.writeObject(p);
// 释放资源
oos.close();
}
public class Person implements Serializable {
private static final long serialVersionUID = -2071565876962058344L;//加入ID
private String name;
private transient int age;//使用transient关键字声明不需要序列化的成员变量
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}

8:Properties集合

Properties:属性集合类。是一个可以和IO流相结合使用的集合类。

Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 

是Hashtable的子类,说明是一个Map集合。

(1)特殊功能:

public Object setProperty(String key,String value):添加元素

public String getProperty(String key):获取元素

public Set<String> stringPropertyNames():获取所有的键的集合

(2)Properties和IO流的结合使用,这里的集合必须是Properties集合

public void load(Reader reader):把文件中的数据读取到集合中

public void store(Writer writer,String comments):把集合中的数据存储到文件

private static void myStore() throws IOException {
// 创建集合对象
Properties prop = new Properties();

prop.setProperty("Jesus", "27");
prop.setProperty("Donald", "30");
prop.setProperty("Lucy", "18");

//public void store(Writer writer,String comments):把集合中的数据存储到文件
Writer w = new FileWriter("name.txt");
prop.store(w, "helloworld");
w.close();
}

private static void myLoad() throws IOException {
Properties prop = new Properties();

// public void load(Reader reader):把文件中的数据读取到集合中
// 注意:这个文件的数据必须是键值对形式
Reader r = new FileReader("prop.txt");
prop.load(r);
r.close();

System.out.println("prop:" + prop);
}
10:NIO

 NIO其实就是新IO的意识。NIO包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。

JDK7的之后的NIO:

JDK7的之后的nio:

Path:路径

Paths:有一个静态方法返回一个路径

public static Path get(URI uri)

Files:提供了静态方法供我们使用

public static long copy(Path source,OutputStream out):复制文件

public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption...options)

五、流的操作规律

之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。

想要知道对象的开发时用到哪些对象,只要通过四个明确即可。

1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer

2、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream 
到这里,就可以明确需求中具体要使用哪个体系。

3、明确具体的设备
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流

4、是否需要其他额外功能
是否需要高效(缓冲区):
是,就加上buffer
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: