1.流的分类
分类一:
①文件流:
FileReader / FileWriter
FileInputStream / FileOutputStream
②缓冲流:
BufferedReader / BufferedWriter
BufferedInputStream / BufferedOutputStream
③对象流: ----涉及序列化、反序列化
ObjectInputStream / ObjectOutputStream
④数据流:
DataInputStream / DataOutputStream
⑤随机存取文件流:
RandomAccessFile
转换流:
⑥InputStreamReader / OutputStreamWriter
标准输入/输出流:
⑦打印流:
PrintStream / PrintWriter
分类二:
按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
按数据流的流向不同分为:输入流,输出流
分类三:
节点流:节点流可以从一个特定的数据源读写数据
处理流:处理流是“连接”在已存在的流(节点流或处理流)之上,通过对数据的 处理为程序提供更为强大的读写功能。
处理流中包含缓冲流、转换流、输入输出流、打印流、数据流、对象流。
2.文件复制
(1)java.io.File类:
文件和目录路径名的抽象表示形式,与平台无关。
File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
代码如下:
public void testFile() throws Exception {
// 定位d盘下
File file = new File("d://test.txt");
// 创建test.txt文件
file.createNewFile();
File file2 = new File("d://test");
// 创建test文件夹
file2.mkdir();
}
这样就会在d盘下创建一个test.txt文件和一个test文件夹。
(2)文件的复制
public void testCopy() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("1.txt");
fos = new FileOutputStream("1.txt.bak");
byte[] buf = new byte[1024];
int realCount = fis.read(buf);
while (realCount != -1) {
fos.write(buf, 0, realCount);
realCount = fis.read(buf);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这种方式可以复制所有的文件。复制时是按字节为单位来复制的,其中buf数组是缓冲数组,作用是提高效率。但是一般操作文本文件不用这种方式。流是一种资源,用完需要手动关闭。
(3)文本文件复制
public void testTextCopy() {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("1.txt");
fw = new FileWriter("2.txt");
char[] cbuf = new char[1024];
int realCount = fr.read(cbuf);
while (realCount != -1) {
fw.write(cbuf, 0, realCount);
realCount = fr.read(cbuf);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这种方式只能复制文本文件,复制时是按字符为单位来复制的,效率比用字节流高。
(4)利用字节缓冲流复制文件
public void testBufferedCopy() {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream("1.txt");
fos = new FileOutputStream("3.txt");
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] buf = new byte[1024];
int realCount = bis.read(buf);
while (realCount != -1) {
bos.write(buf, 0, realCount);
bos.flush();
realCount = bis.read(buf);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这中方式利用缓冲流提高传输效率。缓冲流中自带缓冲,所以不定义缓冲数组也可以。通常会在调用write()方法调用之后调用flush()刷新一下缓冲流,否则有时会存留在缓冲区而不写入。在关闭流的时候,只需要关闭高级流(缓冲流)即可,因为高级会自动关闭低级流。
(5)利用字符缓冲流复制文本文件
public void testBufferedTextCopy() {
FileReader fr = null;
FileWriter fw = null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
fr = new FileReader("1.txt");
fw = new FileWriter("4.txt");
br = new BufferedReader(fr);
bw = new BufferedWriter(fw);
String line = br.readLine();
if (line != null) {
bw.write(line);
line = br.readLine();
}
while (line != null) {
bw.newLine();
bw.write(line);
line = br.readLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
BufferedReader中有readLine()方法,可以读一行,但是将换行符去掉了,所以在write()时需要调用newLine()方法重新换行。
String line = br.readLine();
if (line != null) {
bw.write(line);
line = br.readLine();
}
while (line != null) {
bw.newLine();
bw.write(line);
line = br.readLine();
}
其中这段代码能保证复制后的内容与之前的一模一样,否则会出现多空行的问题。
(6)利用转换流文本文件复制
@Test
public void testConvertTextCopy() {
FileInputStream fis = null;
FileOutputStream fos = null;
InputStreamReader isr = null;
OutputStreamWriter osw = null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
fis = new FileInputStream("1.txt");
fos = new FileOutputStream("5.txt");
isr = new InputStreamReader(fis);
osw = new OutputStreamWriter(fos);
br = new BufferedReader(isr);
bw = new BufferedWriter(osw);
String line = br.readLine();
if (line != null) {
bw.write(line);
line = br.readLine();
}
while (line != null) {
bw.newLine();
bw.write(line);
line = br.readLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这种方式是用转换流将字节流转换为字符流,然后再套上缓冲流进行文本文件的复制的。这里需要注意的是,只能将字节流转换为字符流,不能反过来将字符流转换为字节流,而且只能将文本文件进行转换,否则没有任何意义。
3.对象流
ObjectInputStream和OjbectOutputSteam 用于存储和读取对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
序列化(Serialize):用ObjectOutputStream类将一个Java对象写入IO流中。
反序列化(Deserialize):用ObjectInputStream类从IO流中恢复该Java对象。
ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
详细介绍请看序列化专题。
4.RandomAccessFile类
RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件。支持只访问文件的部分内容,也可以向已存在的文件后追加内容。
RandomAccessFile对象包含一个记录指针,用以标示当前读写处的位置。RandomAccessFile 类对象可以自由移动记录指针:
long getFilePointer():获取文件记录指针的当前位置。
void seek(long pos):将文件记录指针定位到 pos 位置。
构造器
public RandomAccessFile(File file, String mode)
public RandomAccessFile(String name, String mode)
创建RandomAccessFile类实例需要指定一个mode参数,该参数指定RandomAccessFile 的访问模式:
r: 以只读方式打开。
rw:打开以便读取和写入。
rwd:打开以便读取和写入;同步文件内容的更新。
rws:打开以便读取和写入;同步文件内容和元数据的更新。
测试代码如下:
@Test
public void tesRandomAccessFile() {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
raf1 = new RandomAccessFile("1.txt", "rw");
raf2 = new RandomAccessFile("6.txt", "rw");
raf1.seek(9);
byte[] buf = new byte[1024];
int realCount = raf1.read(buf);
while (realCount != -1) {
raf2.write(buf, 0, realCount);
realCount = raf1.read(buf);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf1 != null) {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (raf2 != null) {
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
上面代码是利用RandomAccessFile类实现文件的复制。注意这里的复制不是完全的复制,因为通过调用seek()方法将指针移到第9个位置,所以读取文件时从第9个开始。RandomAccessFile类的功能很强大。
by Karl