流可以使用两种方式分类:源流,也被称为输入流、初始化数据流;宿流,也被称作输出流、终止数据流。源流和宿流也被称作节点流。流只是连续的数据流,就像保存许多数据的数组,它没有索引的概念。不能在流中来回移动, 数据只能顺序访问。
java中的流有两种类型:面向字节流和面向字符流。面向字节流操作数据的字节,面向字符流操作字符,通常是Unicode字符集。
InputStream和OutputStream类操作字节数据。Reader和Writer类工作在字符上。File类为物理文件提供接口(Path类是File类的替代品,并且提供了更复杂的功能)。
面向字节流工作在8位编码上,面向字符流工作在16位Unicode编码上。InputStream和OutputStream都是抽象类,各种面向字节流的类派生了它们的功能,相关的有子类:ByteArrayInputStream、FileInputStream、ObjectOutputStream和PipeInputStream。
字节流
这里我们处理文本文件时,使用面向字符流的类,其中每个字符(Unicode字符)由两个字节数据组成。
检查物流文件长度最简单的方法就是以二进制模式打开文件。当使用基于InputStream和OutputStream的面向字节的类时,文件将以二进制模式打开。当基于Reader和Writer面向字符的类时,文件将以字符模式打开。下面是计算一个文件长度的示例:
int count = 0;
InputStream streamReader = null;
File filePath = new File(/*文件路径*/); //要计算大小的文件
try {
streamReader = new FileInputStream(filePath);
//每次读取文件的一个字节
while(streamReader.read() != -1) {
count++;
}
System.out.println("文件大小:" + count);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
streamReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
复制文件内容:
InputStream readerStream = null;
OutputStream writeStream = null;
//通常情况下,缓冲区的分配是512的倍数——磁盘扇区大小的典型值
byte[] buffer = new byte[512];
int numberRead = 0;
try {
readerStream = new FileInputStream(readFile);
writeStream = new FileOutputStream(writeFile);
while((numberRead = readerStream.read(buffer)) != -1) {
writeStream.write(buffer, 0, numberRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
readerStream.close();
writeStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
当numberRead的值为-1的时候表示已经到达文件的末尾。读取的字节数通常等于缓冲区的长度,但是如果在缓冲区被完全填满之前,就发生了EOF(end of file)的情形,读取的字节数目可能变少。
OutPutStream
OutPutStream类定义了3个重载的Write方法:
public abstract void write(int b) throws IOException
public void write(byte[]b)throws IOException
public void write(byte[] b, int off, int len) throws IOException
flush方法刷新缓冲区的内容到输出流:
public void flush() throws IOException
如果想强制立即写入文件缓冲区,可使用flush。
FileOutputStream构造函数有一个变体:
public void FileOutputStream(String name, boolean append) throws FileNotFoundException
可以通过制定append参数是否以附加模式打开文件。
字符流
文件查看的示例:
int numberRead = 0;
FileReader reader = null;
PrintWriter writer = null;
char buffer[] = new char[512];
try {
reader = new FileReader(readFile);
writer = new PrintWriter(System.out);
while ((numberRead = reader.read(buffer)) != -1) {
writer.write(buffer, 0, numberRead);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
writer.close();
}
访问主机文件系统
目录列举程序:
Path dirPath = Paths.get("filePath");
DirectoryStream<Path> directoryStream = null;
try {
directoryStream = Files.newDirectoryStream(dirPath);
for(Path path : directoryStream) {
System.out.println(path.getFileName());
}
} catch (IOException e) {
e.printStackTrace();
}
目录过滤可用:
directoryStream = Files.newDirectoryStream(dirPath, "*.{java}");
读写对象
ObjectOutputStream writer = null;
ObjectInputStream reader = null;
try {
//如果同名文件已经存在,这里将覆盖原有内容
writer = new ObjectOutputStream(new FileOutputStream("student.bat"));
writer.writeObject(new Student(0, "0first", "0last"));
writer.writeObject(new Student(1, "1first", "1last"));
writer.writeObject(new Student(2, "2first", "2last"));
reader = new ObjectInputStream(new FileInputStream("student.bat"));
for(int i = 0; i < 3; i++) {
System.out.println(reader.readObject());
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
writer.close();
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
注意Student类实现了Serializable