Java中文件读写
2013-01-20
分析
开篇即开扯,数年前,我被某人问道java如何进行文件读写,具体:从FileA
中读取内容,并追加写入FileB
内。我一听,简单呀,几个步骤:
- Java中找到两个文件
FileA
和FileB
; - 打开文件
FileA
和FileB
; - 读取文件
FileA
的内容; - 将读取的文件
FileA
内容追加到FileB
后; - 关闭文件
FileA
和FileB
;
打完收工,简简单单;然后,某人递给我一张纸,“把上述过程的java代码写到纸上吧”。沉思2分钟,我x,“我不会”。
文件读写的基本原理
(涉及到stream层面的内容)
- FileInputStream、FileOutputStream:read(byte[])和write(byte[], int, int)
- InputStreamReader(利用:inputStream、FileInputStream)、OutputStreamWriter(利用:outputStream、FileOutputStream)
- FileReader、FileWriter(实际上为上述StreamReader和StreamWriter的子类)
补充梳理:
- FileInputStream:byte–InputStreamReader–FileReader:char
- 通过在InputStreamReader外封装一层BufferedReader,增加文件读取效率。
- 下面两种情景下,一定要使用Reader,而不能简单的使用Stream:
- 读取文件,并进行正则匹配时:
InputStreamReader(InputStream, String charset)
,推荐利用BufferedReader(Reader)
,其可以按行读取内容; - 读取文件,转换为另一种编码方式存储时:
InputStreamReader(InputStream, String charsetIn)
OutputStreamWriter(OutputStream, String charsetOut)
- 小结:上述核心,char转换为byte之后,可以转换为任意编码方式的char
- 读取文件,并进行正则匹配时:
(涉及到class之间的继承关系,简洁的应用代码)
读取文件,两个维度:
- 按行,读写文件;
BufferedReader.readLine()
BufferedWrite.newLine()
- 按缓存空间,读写文件:
Reader.read(char[])
Writer.write(char[], int, int)
FileInputStream.read(byte[])
FileOutputStream.write(byte[], int, int)
- 调用缓存机制;
BufferedReader(Reader)
、BufferedWriter(Writer)
BufferedInputStream(InputStream)
、BufferedOutputStream(OutputStream)
分类:byte和char
差异:char是人眼可以识别的内容,可用于进行正则匹配或搜索;但需要经过一次byte与char之间的转换;
疑问:到底有什么差异?上面只是自己直观的感受,可能有误差;需要查证一下,产生两种方式的原因;
按char读写
字符,是人眼可以识别的内容,可以进行正则匹配;java.io.Reader
和java.io.Writer
,按字符(character)读写文件,具体几种方式:
java.io.FileReader
和java.io.FileWriter
- 默认的编码方式(系统编码)
- 默认的byte-buffer size
- 读写操作:
- 读取:
charLen = FileReader.read(char[] charBuf)
- 循环条件:
charLen != -1
- 写入:
FileWriter.write(charBuf, 0, charLen)
- 读取:
java.io.InputStreamReader
和java.io.OutputStreamWriter
- 编码方式:初始化对象时指定,
InputStreamReader(InputStream, charset)
- 编码方式:初始化对象时指定,
OutputStreamWriter(OutputStream, charset)
- 两个Stream:FileInputStream、FileOutputStream;
- 编码方式:初始化对象时指定,
java.io.BufferedReader
和java.io.BufferedWriter
- 初始化对象:
BufferedReader(Reader)
BufferedWriter(Writer)
- 按行读取、按行写入、追加换行:
BufferedReader.readLine() != null
BufferedWriter.write(String)
BufferedWriter.newLine()
- 初始化对象:
按byte读写
字节,机器识别的内容;java.io.InputStream
和java.io.OutputStream
,具体几种方式:
java.io.FileInputStream
和java.io.FileOutputStream
;- 读取:
byteLen = FileInputStream.read(byte[] byteBuf)
- 循环条件:
byteLen != -1
- 写入:
FileOutputStream.write(byteBuf, 0, byteLen)
- 读取:
java.io.BufferedInputStream
和java.io.BufferedOutputStream
- 初始化对象:
BufferedInputStream(InputStream)
BufferedOutputStream(OutputStream)
- 读写文件,具体参照
FileInputStream
和FileOutputStream
;
- 初始化对象:
思考:Buffered中详细的机制,特别是其中几个方法:mark()
、skip()
、reset()
、ready()
等等;
FileReader & FileWriter
java.io.FileReader和java.io.FileWriter,几点:
- 以character来读写文件;
- default character encoding;
- default byte-buffer size;
疑问:byte-buffer size
什么东西?
程序的处理过程,几点:
- 新建实例:FileReader和FileWriter
- 为存储从FileReader中读取的内容,新建:
char[] bufChar = new char[100]
int bufLen = -1
- 循环读取和写入
- 终止条件:
(bufLen = fileReader.read(bufChar)) != -1
- 写入新文件:
fileWriter(bufChar, 0, bufLen)
- 终止条件:
- 刷新并关闭数据流:
fileWriter.flush()
fileWriter.close()
fileReader.read()
核心代码:
File srcFile = new File(srcFilename);
File destFile = new File(destFilename);
FileReader srcFileReader = new FileReader(srcFile);
FileWriter destFileWriter = new FileWriter(destFile);
char[] bufChar = new char[1000];
int bufLen = -1;
while( (bufLen = srcFileReader.read(bufChar)) != -1 ){
destFileWriter.write(bufChar, 0, bufLen);
Arrays.fill(bufChar, '\0');
}
destFileWriter.flush();
destFileWriter.close();
srcFileReader.close();
完整示例代码如下:
package com.github.ningg;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
public class TestFile {
public static void main(String[] args) throws IOException {
String srcFilePath = "E:/2.log";
String destFilePath = "E:/2char.log";
File srcFile = new File(srcFilePath);
File destFile = new File(destFilePath);
FileReader fileReader = new FileReader(srcFile);
FileWriter fileWriter = new FileWriter(destFile);
char[] charArray = new char[1000];
int charLen = -1;
while ( (charLen = fileReader.read(charArray)) != -1) {
System.out.println(Arrays.toString(charArray));
fileWriter.write(charArray, 0, charLen);
Arrays.fill(charArray, '\0');
};
fileWriter.flush();
fileReader.close();
fileWriter.close();
}
}
疑问:上述FileReader.read()
和FileWriter.write()
,其中,write()
本质是覆盖写,是否有追加写?
FileWriter.write(String filename)
:- 若filename对应文件不存在,则程序自动创建;
- 若filename对应文件为只读,则抛出异常;
- 若filename对应文件已被打开,并且OS限制只允许一个进程占用文件,则抛出异常;
FileWriter.write(String filename, boolean append)
:boolean append
字段,设置为true
时,将以追加
方式写入文件;- 默认,以
覆盖
方式写入文件;
疑问:按照char的方式读写文件时,FileReader
和FileWriter
利用了默认的编码方式,通常是UTF-8
;那,有没有按照char方式读写文件,同时可以指定charset
的办法呢?
InputStreamReader & OutputStreamWriter
完整示例代码如下:
package com.github.ningg;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
public class InputStreamReaderAndOutputStreamWriter {
public static void main(String[] args) throws IOException {
String charset = "GBK";
String srcFilepath = "E:/1.log";
String destFilepath = "E:/1char.log";
FileInputStream srcFileInputStream = new FileInputStream(srcFilepath);
FileOutputStream destFileOutputStream = new FileOutputStream(destFilepath);
InputStreamReader srcStreamReader = new InputStreamReader(srcFileInputStream, charset);
OutputStreamWriter destStreamWriter = new OutputStreamWriter(destFileOutputStream, charset);
char bufChar[] = new char[1000];
int bufLen = -1;
while( (bufLen = srcStreamReader.read(bufChar)) != -1 ){
destStreamWriter.write(bufChar, 0, bufLen);
System.out.println(Arrays.toString(bufChar));
Arrays.fill(bufChar, '\0');
}
destStreamWriter.flush();
destStreamWriter.close();
srcStreamReader.close();
}
}
BufferedReader & BufferedWriter
思考:BufferedReader和BufferedWriter的实现机制?
- BufferedReader:
- 缓存空间:
BufferedReader(Reader)
和BufferedReader(Reader, int bufSize)
;- 默认buffer size:8192(8K char),能够满足大部分需要;
- 按行读取;
BufferedReader.readLine()
:读取下一行的内容,不包含换行符
;readLine() == null
为文章末尾;
- 缓存空间:
- BufferedWriter:
- 缓存空间:
BufferedWriter(Writer)
和BufferedWriter(Writer, int bufSize)
;- 默认buffer size:8192(8K char),能满足大部分需要;
- 写入数据:
BufferedWriter.wirte(String)
:写入数据- 增加换行符:
BufferedWriter.newLine()
- 缓存空间:
完整示例代码如下:
package com.github.ningg;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class BufferedReaderAndBufferedWriter {
public static void main(String[] args) throws IOException {
String srcFile = "E:/1.log";
String destFile = "E:/lbuf.log";
String charset = "GBK";
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charset);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charset);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
String inputLine = null;
while((inputLine = bufferedReader.readLine()) != null ){
bufferedWriter.write(inputLine);
bufferedWriter.newLine();
System.out.println(inputLine);
}
bufferedWriter.flush();
bufferedWriter.close();
bufferedReader.close();
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
}
}
思考:几个方法的作用,以及联系:
- 输出数据时,flush():
- FileOutputStream:自身flush()
- FileWriter:本质,OutputStream.flush()
- OutputStreamWriter:本质,调用OutputStream.flush()
- BufferedWriter:本质,调用Writer.flush()
- 输出数据时,close():
- FileOutputStream
- FileWriter
- OutputStreamWriter
- BufferedWriter
- 读取数据时,close():
- FileInputStream
- FileReader
- InputStreamReader
- BufferedReader
小结:只要最高级的Reader、Writer、InputStream、OutputStream,完成flush\close,则无需向下递归;
备注:上述InputStream、OutputStream、Reader、Writer,之间关系的图形化表述;(TODO:需要一张图来表示其中的联系)
FileInputStream & FileOutputStream
完整示例代码如下:
package com.github.ningg;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class FileInputStreamAndFileOutputStream {
public static void main(String[] args) throws IOException {
String srcFilepath = "E:/1.log";
String destFilepath = "E:/1byte.log";
FileInputStream srcInputStream = new FileInputStream(srcFilepath);
FileOutputStream destOutputStream = new FileOutputStream(destFilepath);
byte[] bufByte = new byte[1000];
int bufLen = -1;
while( (bufLen = srcInputStream.read(bufByte)) != -1 ){
destOutputStream.write(bufByte, 0, bufLen);
System.out.println(Arrays.toString(bufByte));
}
destOutputStream.flush();
destOutputStream.close();
srcInputStream.close();
}
}
BufferedInputStream & BufferedOutputStream
完整示例代码如下:
package com.github.ningg;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedInputStreamAndBufferedOutputStream {
public static void main(String[] args) throws IOException {
String srcFile = "E:/1.log";
String destFile = "E:/1BufByte.log";
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
byte[] byteBuf = new byte[1000];
int byteLen = -1;
while( (byteLen = bufferedInputStream.read(byteBuf)) != -1 ){
bufferedOutputStream.write(byteBuf, 0, byteLen);
}
bufferedOutputStream.flush();
bufferedOutputStream.close();
bufferedInputStream.close();
}
}
参考来源
TODO
几点:
- Java Tutorials:Basic I/O,需要阅读一遍,当前没有阅读;
- File相关的Stream机制,特别是,为什么有Reader、又有Stream?底层实现有什么差异?适用场景?
- buffered机制中,skip、mark、reset等方法的用途?
原文地址:https://ningg.top/java-file/