Java中比较丰富的I/O操作,使得Java能够被众多公司接受的一个优势之一。
数据流的概念和技术家奴啊了堆文件I/O的理解、处理以及操作。数据流指一定字节长度和方向的线性有序数据。虽然输入、输出数据都以线性有序字节流的形式存在,但这些数据流的内容可以构成不同文件格式:文本文件、二进制文件、对象文件、压缩文件等等。
Java中的I/0须知道以下内容:
文件的格式、文件内容、数据流方向、文件路径和缓冲。
1.基本知识
stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。在
Java的I/O中,所有的stream(包括Input和Out stream)都包括两种类型:
以字节为导向的stream 以字节为导向的stream,表示以字节为单位从stream中读取或往stream中写入信息。以字
节为导向的stream包括下面几种类型:
1) input stream:
1) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
2) StringBufferInputStream:把一个String对象作为InputStream
3) FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
4) PipedInputStream:实现了pipe的概念,主要在线程中使用
5) SequenceInputStream:把多个InputStream合并为一个InputStream
2) Out stream
1) ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
2) FileOutputStream:把信息存入文件中
3) PipedOutputStream:实现了pipe的概念,主要在线程中使用
4) SequenceOutputStream:把多个OutStream合并为一个OutStream
以Unicode字符为导向的stream(我个人比较喜欢这个,easy,fast),表示以Unicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几种类型: 1) Input Stream
1) CharArrayReader:与ByteArrayInputStream对应
2) StringReader:与StringBufferInputStream对应
3) FileReader:与FileInputStream对应
4) PipedReader:与PipedInputStream对应
2) Out Stream
1) CharArrayWriter:与ByteArrayOutputStream对应
2) StringWriter:无与之对应的以字节为导向的stream
3) FileWriter:与FileOutputStream对应
4) PipedWriter:与PipedOutputStream对应
以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现
的功能相同,字是在操作时的导向不同。如CharArrayReader:和ByteArrayInputStream的
作用都是把内存中的一个缓冲区作为InputStream使用,所不同的是前者每次从内存中读取
一个字节的信息,而后者每次从内存中读取一个字符。
负责字符流和字节流之间转换的工作有InputStreamReader和OutputStreamReader来完成。把一个以字节为导向的stream转换成一个以字符为导向的stream。
stream添加属性:
运用上面介绍的Java中操作IO的API,我们就可完成我们想完成的任何操作了。但通过Fil
terInputStream和FilterOutStream的子类,我们可以为stream添加属性。下面以一个例子
来说明这种功能的作用。
如果我们要往一个文件中写入数据,我们可以这样操作:
FileOutStream fs = new FileOutStream(“test.txt”);
然后就可以通过产生的fs对象调用write()函数来往test.txt文件中写入数据了。但是,如
果我们想实现“先把要写入文件的数据先缓存到内存中,再把缓存中的数据写入文件中”
的功能时,上面的API就没有一个能满足我们的需求了。但是通过FilterInputStream和Fi
lterOutStream的子类,为FileOutStream添加我们所需要的功能。
FilterInputStream的各种类型
用于封装以字节为导向的InputStream
1) DataInputStream:从stream中读取基本类型(int、char等)数据。
2) BufferedInputStream:使用缓冲区
3) LineNumberInputStream:会记录input stream内的行数,然后可以调用getLineNumber()和setLineNumber(int)
4) PushbackInputStream:很少用到,一般用于编译器开发.
用于封装以字符为导向的InputStream
1) 没有与DataInputStream对应的类。除非在要使用readLine()时改用BufferedReader,否则使用DataInputStream
2) BufferedReader:与BufferedInputStream对应
3) LineNumberReader:与LineNumberInputStream对应
4) PushBackReader:与PushbackInputStream对应
FilterOutStream的各种类型
用于封装以字节为导向的OutputStream
1) DataIOutStream:往stream中输出基本类型(int、char等)数据。
2) BufferedOutStream:使用缓冲区
3) PrintStream:产生格式化输出
用于封装以字符为导向的OutputStream
1) BufferedWriter:与对应
2) PrintWriter:与对应
RandomAccessFile
1) 可通过RandomAccessFile对象完成对文件的读写操作
2) 在产生一个对象时,可指明要打开的文件的性质:r,只读;w,只写;rw可读写
3) 可以直接跳到文件中指定的位置
2. File
File类是基础类,作为文件操作的对象。既可以是文件,也可以是目录。
(1)四个静态常量:
static String pathSeparator |
与系统有关的路径分隔符,为了方便,它被表示为一个字符串。 |
static char pathSeparatorChar |
与系统有关的路径分隔符。 |
static String separator |
与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。 |
static char separatorChar |
与系统有关的默认名称分隔符 |
其中,pathSeparator作为分隔符来区分不同的路径(在Windows下是;(分号),在Linux下是:(冒号))。separator是路径中使用的分隔符(在Windows下是\,在Linux下是/)。
在File类中有很多有用的方法,可以参考阅读API。但是其中的如下方法要列出来说明下。
String[] list() |
返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 |
String[] list(FilenameFilter filter) |
返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 |
File[] listFiles() |
返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 |
File[] listFiles(FileFilter filter) |
返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 |
File[] listFiles(FilenameFilter filter) |
返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 |
static File[] listRoots() |
列出可用的文件系统根。 |
在下面的例子中使用了上面表格中列出的内容。
package com.java.io;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
public class IO {
public static void main(String[] args) {
System.out.println("---------------------- Separator ----------------------");
System.out.println("pathSeparator: "+File.pathSeparator + "\t" + "separator: " + File.separator);
System.out.println("---------------------- List Roots ----------------------");
File[] roots = File.listRoots();
for(File file : roots){
System.out.print(file + "\t");
}
System.out.println();
System.out.println("---------------------- List ----------------------");
File file = new File("F:\\");
System.out.print("List:\t\t\t\t");
String[] fileNames = file.list();
for(String name : fileNames){
System.out.print(name + "\t");
}
System.out.println();
System.out.print("List(filter):\t\t\t");
String[] _fileNames = file.list(new FilenameFilter(){
@Override
public boolean accept(File file, String name) {
return file.isDirectory() && name.contains("E");//列出名字中有大写E的文件夹
}
});
for(String name : _fileNames){
System.out.print(name + "\t");
}
System.out.println();
System.out.print("ListFiles():\t\t\t");
File[] files = file.listFiles();
for(File _file : files){
System.out.print(_file + "\t");
}
System.out.println();
System.out.print("ListFiles(FilenameFilter):\t");
File[] _files = file.listFiles(new FilenameFilter(){
@Override
public boolean accept(File file, String name) {
return file.isDirectory() && name.contains("E");//列出名字中有大写E的文件夹
}
});
for(File _file : _files){
System.out.print(_file + "\t");
}
System.out.println();
System.out.print("ListFiles(FileFilter):\t\t");
File[] __files = file.listFiles(new FileFilter(){
@Override
public boolean accept(File file) {
return file.isDirectory() && file.getName().contains("E");
}
});
for(File _file : __files){
System.out.print(_file + "\t");
}
System.out.println();
}
}
结果:
---------------------- Separator ----------------------
pathSeparator: ; separator: \
---------------------- List Roots ----------------------
C:\ D:\ E:\ F:\ G:\ H:\
---------------------- List ----------------------
List: 579492bc12f33c12d7238760d8111512 Eclipse FavoriteVideo KwDownload Lectures RECYCLER System Volume Information
List(filter): Eclipse RECYCLER
ListFiles(): F:\579492bc12f33c12d7238760d8111512 F:\Eclipse F:\FavoriteVideo F:\KwDownload F:\Lectures F:\RECYCLER F:\System Volume Information
ListFiles(FilenameFilter): F:\Eclipse F:\RECYCLER
ListFiles(FileFilter): F:\Eclipse F:\RECYCLER
3. 比较常用的I/O操作。
FileInputStream/BufferedInputStream
FileOutputStream/BufferedOutputStream/PrintStream
FileReader/BufferedReader/InputStreamReader
FileWriter/BufferedWriter/OutputStreamWriter
Java中的管道模型,很好的对一层层的处理进行了封装,这使得Java的I/O处理使用起来相当灵活。一些常用的封装有:
BufferedReader reader = new BufferedReader(new FileReader(new File("c:\\test.txt"))); //读取文件1
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("c:\\test.txt"))); //读取文件2
InputStreamReader isr= new InputStreamReader(new FileInputStream(new File("c:\\test.txt"))); //读取文件3
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("c:\\test.txt"))); //写文件1
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("c:\\test.txt"))); //写文件2
OutputStreamWriter osw= new OutputStreamWriter(new FileOutputStream(new File("c:\\test.txt"))); //写文件3
System.setOut(new PrintWriter(new File("c:\\test.txt"))); //改变输出,将输出重定向到文件中
4. 按照上面的介绍,如果想使用某一个管道模式来读写文件将会变得非常简单,只要查看下API文档,按照上面的结构很容易就能够实现自己想要的功能。
下面是一个简单的例子。
package com.java.io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintStream;
public class IO1 {
public static void main(String[] args) {
LineNumberReader reader = null;
try {
System.setOut(new PrintStream(new File("d:\\test2.txt")));
reader = new LineNumberReader(new FileReader(new File("d:\\test.txt")));
String line = "";
while((line = reader.readLine()) != null){
int number = reader.getLineNumber();
System.out.println(number + "\t" + line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(reader != null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注:d:\test.txt 文件如附件,运行前该文件是存在的。运行程序之后,在d盘根目录下会生成一个test2.txt的文件,里面的内容如附件test_test2.rar。
5. Object读写事例
package com.java.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class OBJ_IO {
public static void WriteOBJ(Person person, String fileName){
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(new File(fileName)));
oos.writeObject(person);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static Person readerPersonOBJ(String fileName){
Person person = null;
ObjectInputStream oos = null;
try {
oos = new ObjectInputStream(new FileInputStream(new File(fileName)));
person = (Person)oos.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally{
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return person;
}
public static void main(String[] args) {
String fileName = "d:\\person.obj";
Person person = new Person("Eric",22);
WriteOBJ(person, fileName);
person = readerPersonOBJ(fileName);
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
class Person implements Serializable{
private static final long serialVersionUID = -6018738718323071804L;
private String name;
private int age;
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;
}
}
结果:
Eric
22
(注:在d盘会生成一个person文件,如附件person.obj.zip)
6. RandomAccessFile类
该类似于C++中的文件读取,可以查看相关API文档进行阅读。
7. 压缩文件的读取操作。
在java.util.zip目录下有GZIPInputStream GZIPOutputStream ZipInputStream 和 ZipOutputStream等类。以Zip来事例如何生成并读写Zip文件。
package com.java.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class Zip {
/**
*
* @param content 要写到压缩包内文件的内容
* @param fileName 相当于最外面压缩包的名字
* @param entryName 相当于压缩包内文件的名字
*/
public static void writeZip(String content, String fileName, String entryName){
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(new FileOutputStream(new File(fileName)));
zos.setMethod(ZipOutputStream.DEFLATED);//设置压缩方法
zos.putNextEntry(new ZipEntry(entryName));
byte[] bytes = content.getBytes();
int off = 0;
int len = bytes.length;
zos.write(bytes, off, len);
zos.finish();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(zos != null){
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void readZip(String fileName){
ZipInputStream zis = null;
try {
File file = new File(fileName);
zis = new ZipInputStream(new FileInputStream(file));
while(zis.getNextEntry() != null){
byte[] bytes = new byte[1024];
int temp = -1;
int index = 0;
while((temp = zis.read()) != -1){
bytes[index++] = (byte)temp;
}
System.out.println(new String(bytes,0,index));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String fileName = "d:\\test.zip";
String content1 = "This is test content";
writeZip(content1, fileName, "content.txt");
readZip(fileName);
}
}
结果:
This is test content
(注:会在d盘生成一个test.zip文件。见附件test.zip)