public class FileWriterDemo {
public static void main(String[] args) throws IOException {
// 创建一个FileWriter对象
FileWriter fw = new FileWriter("FileWriterDemo.txt");
// 调用write方法,将字符串写到流中
fw.write("hello wrold!");
}
}
当执行上述代码时,FileWriterDemo.txt文件上并没有任何字符。原因:FileWriter对象其实先把数据写入到了缓冲区中,所以需要使用flush()方法,或
// 刷新流对象中的缓冲中的数据
// fw.flush();
// 关闭流资源,关闭前会刷新一次内部的缓冲数据
fw.close();
flush()方法与close()方法区别:flush刷新后,流还可以使用;close刷新后,流关闭。
FileWriter(File file, boolean append)提供这个方法,当第二个参数为true
,则将字节写入文件末尾处,而不是写入文件开始处。
(1)字符输入流 Reader
用于读取字符流的抽象类。子类必须实现的方法只有read(char[], int, int) 和 close()。
/*
* 第一种方式:通过每次取出一个字符的方式读取
* read()返回的字符的10进制数字.
*/
public class FileReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
try {
// 创建一个文件读取流对象,和指定名称的文件相关联.
fr = new FileReader("FileWriterDemo.txt");
int ch = -1;
while ((ch = fr.read()) != -1) {
System.out.println((char) ch);
}
} catch (IOException e) {
System.out.println(e.toString());
} finally {
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 第二种方式:通过字符数组进行读取.
fr = new FileReader("FileWriterDemo.txt");
// 定义一个字符数组,用于存储读取到的字符
// 该read(char[])返回的是读到的字符个数
char[] ch = new char[1024];
int num = 0;
while ((num = fr.read(ch)) != -1) {
System.out.println(new String(ch, 0, num));
}
综合使用字符输出输出流:
// 从一个文件中读取出里面所有数据,然后写入另一个文件中
FileReader fr = new FileReader("demo.txt");
FileWriter fw = new FileWriter("demo2.txt");
char[] buf = new char[1024];
int len = 0;
while ((len = fr.read(buf)) != -1) {
fw.write(new String(buf, 0, len));
}
fw.close();
fr.close();
为了提高对流的操作效率,使用了字符的缓冲区。
readLine()方法的原理:
其实缓冲区中的该方法,用的还是与缓冲区关联的流对象的read方法。只不过,每一次读到一个字符,先不进行具体操作,先进行临时存储。当读取到回车标记时,将临时容器中存储的数据一次性返回。
// 复制方法1:
public static void copy_1() throws IOException {
FileInputStream fis = new FileInputStream("D:\\0.mp3");
FileOutputStream fos = new FileOutputStream("D:\\1.mp3");
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.close();
fis.close();
}
// 方法2:已经用了缓冲流就不用再用缓冲区byte[] buf 了
public static void copy_2() throws IOException {
FileInputStream fis = new FileInputStream("D:\\0.mp3");
FileOutputStream fos = new FileOutputStream("D:\\2.mp3");
BufferedInputStream bufis = new BufferedInputStream(fis);
BufferedOutputStream bufos = new BufferedOutputStream(fos);
int ch = 0;
while ((ch = bufis.read()) != -1) {
bufos.write(ch);
}
bufos.close();
bufis.close();
}
// 方法3: 不建议,fis.available() 把一个文件大小都读进来了,如果文件过大,内存会用完
public static void copy_3() throws IOException {
FileInputStream fis = new FileInputStream("D:\\0.mp3");
FileOutputStream fos = new FileOutputStream("D:\\3.mp3");
byte[] buf = new byte[fis.available()];
fis.read(buf);
fos.write(buf);
fos.close();
fis.close();
}
// 方法4:读一个写一个,效率很差!
public static void copy_4() throws IOException {
FileInputStream fis = new FileInputStream("D:\\0.mp3");
FileOutputStream fos = new FileOutputStream("D:\\4.mp3");
int ch = 0;
while ((ch = fis.read()) != -1) {
fos.write(ch);
}
fos.close();
fis.close();
}
其中:字节流可以处理所有类型数据,如图片,mp3,avi。如果是处理纯文本数据,就要优先考虑使用字符流。
3、(重点)流操作的基本规律
1. 明确源和目的
源:输入流,Reader、InputStream
目的:输出流,Writer、OutputStream
2. 操作的数据是否是纯文本
是:字符流
不是:字节流
3. 当体系明确后,在明确要使用哪个具体对象
通过设备来区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
范例 . 将键盘录入的数据保存到一个文件中 .设备:键盘,对应的对象是System.in
不是选择Reader嘛? System.in对应的不是字节流InputStream嘛?
为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的.所以既然明确了Reader,那么就将System.in转成Reader.
用Reader体系中的读取转换流InputStreamReader
是否需要提高效率? 是! 用到Reader体系中的BufferedReader.
InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
目的:输出流,Writer、OutputStream
是不是纯文本? 是! 用Writer
设备:硬盘,txt文件.使用FileWriter
是否需要提高效率? 是! 用到Writer体系中的BufferedWriter
FileWriter fw = new FileWriter("xxx.txt");
BufferedWriter bw = new BufferedWriter(fw);
4、流操作的基本规律
Reader和Writer各有一个子类:
|--InputStreamReader:读取转换流
|--OutputStreamWriter:写入转换流
(1) InputStreamReader: 读取转换流
字节流读取的时候用的是一个一个字节的读取方式或者是字节数组的读取方式,
字符流中读取的时候,除了有一个一个字符的读取方式和数组 的读取 方式外 ,在缓冲技术里面有一行一行的读取,这个方法在读取的时候很好用也很方便,那么我们就可以把字节流的转换成字符流,然后利用缓冲对象来使用读取一行的方法。
(2) OutputStreamWriter: 读取转换流charset
将要写入流中的字符编码成字节。public static void main(String[] args) throws IOException {
// 获取键盘录入对象
// InputStream in = System.in;
// 将字节流对象转成字符流对象,使用转换流InputStreamReader
// InputStreamReader isr = new InputStreamReader(in);
// 为了提高效率,将字符串进行缓冲区技术高效操作.使用BufferedReader
// BufferedReader br = new BufferedReader(isr);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
System.out));
String s = null;
while ((s = br.readLine()) != null) {
if (s.equals("over"))
break;
bw.write(s);
bw.newLine();
bw.flush();
}
}
当想要把录入的数据按照指定的编码表
(utf-8)
将数据存储到文件中
,而指定的表码表只有转换流可以指定。
OutputStreamWriter(OutputStream out,String charsetName)
个人理解:通常涉及到字符编码转换时 ,需要用到转换流 .
public static void main(String[] args) throws IOException {
// 源
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
FileOutputStream fos = new FileOutputStream("demo.txt");
// 默认的编码是jbk,这时指定编码为UTF-8
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
String s = null;
while ((s = br.readLine()) != null) {
if (s.equals("over"))
break;
bw.write(s);
bw.newLine();
bw.flush();
}
}
5、IO异常处理方式
public static void main(String[] args) {
// 建立并初始化流
FileReader fr = null;
try {
fr = new FileReader("demo.txt");
// 定义一个字符数组,用于存储读取到的字符
// 该read(char[])返回的是读到的字符个数
char[] ch = new char[1024];
int num = 0;
while ((num = fr.read(ch)) != -1) {
System.out.println(new String(ch, 0, num));
}
} catch (IOException e) {
System.out.println(e.toString());
} finally {
try {
/*
* 防止出现null异常,先判断fw是否为null,当还有其他流时,
* 也应该像这样try_catch,再关闭流
*/
if (fr != null)
fr.close();
} catch (IOException e) {
System.out.println(e.toString());
}
}
}