Java IO篇
- 1. IO概述
- 2. IO流常用基类
-
- 2.1 字节流的抽象基类:
- 2.2 字符流的抽象基类
- 2.3 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
- 3. 字符流的操作
-
- 3.1 读取文件
- 3.2 写出文件
- 3.3 注意事项
- 4. 字符流缓冲区的读写操作
-
- 4.1 自定义缓冲区读写
- 4.2 内置缓冲区的BufferedReader和BufferedWriter
- 5. 装饰设计模式
-
- 5.1 什么情况下使用装饰设计模式
- 5.2 装饰模式的基本格式。
- 5.3 了解BufferedReader、BufferedWriter的原理。
- 6 字节流
-
- 6.1 自定义缓冲区读写
- 6.2 BufferedInputStream、BufferedOutputStream
- 6.3 FileOutputStream
- 6.4 FileInputStream
- 7. 转换流
-
- InputStreamReader
- OutputStreamWriter
- 8. 标准输入,输出
- 9. 流操作小结
1. IO概述
- IO流用来处理设备之间的数据传输
- Java对数据的操作是通过流的方式
- Java用于操作流的对象都在IO包中
- 流按操作对象分为两种:字节流与字符流,字节流可以操作任何数据,字符流只能操作纯字符数据比较方便。
- 流按流向分为:输入流,输出流。
2. IO流常用基类
2.1 字节流的抽象基类:
InputStream
,
OutputStream
2.2 字符流的抽象基类
Reader
,
Writer
2.3 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
- 如:InputStream的子类FileInputStream。
- 如:Reader的子类FileReader。
- InputStreamReader是Reader的子类
3. 字符流的操作
3.1 读取文件
//定义字符流关联指定文件
FileReader reader = new FileReader("Test.txt");
//读取一个字符,返回int,该字符的码表值
int ch = reader.read();
//关闭流,释放资源
reader.close();
3.2 写出文件
//定义字符输出流关联指定文件
FileWriter writer = new FileWriter("Test.txt");
//写出一个字符,接收int码表值
writer.write(97);
//关闭流,释放资源
writer.close();
3.3 注意事项
- 文件路径
- 定义文件路径时Windows中的目录符号为“\”,但这个符号在Java中是特殊字符,需要转义。可以用“\”或“/”表示。
- 读取文件
- 读取文件时必须保证文件存在,否则将抛出FileNotFoundException。
- 写出文件
- 写出时文件如不存在时程序会创建新文件,如文件已存在则会清空原文件内容重新写入。
- 如需追加内容可调用FileWriter构造函数FileWriter(String fileName, boolean append)
4. 字符流缓冲区的读写操作
4.1 自定义缓冲区读写
- 为什么定义缓冲区
- 由于单个字符读写需要频繁操作文件,所以效率非常低。我们可以定义缓冲区将要读取或写出的数据缓存,减少操作文件次数。
- 缓冲区读取
- 先定义一个数组,然后调用
读取一个数组的方法。intFileReader
read(char[] cbuf)
- 先定义一个数组,然后调用
- 缓冲区写出
- 将要写出的数据存放在数组中,调用FileWriter方法,一次写出一个数组。
void write(char[] cbuf, int off, int len)
- 将要写出的数据存放在数组中,调用FileWriter方法,一次写出一个数组。
4.2 内置缓冲区的BufferedReader和BufferedWriter
- Java提供了带缓冲功能的Reader和Writer类:
BufferedReader,BufferedWriter
- 这两个类都是提供包装功能,需要提供其他流来使用,给其他流增加缓冲功能
- 当我们调用
读取数据时,程序会从文件中一次读取8192个字符用来缓冲BufferedReader
- 当我们调用
写出数据时,程序会先将数据写出到缓冲数组,直到写满BufferedWriter
个才一次性刷出到文件8192
- 特有方法
注意:newLine(), readLine()
读取时 不会读取换行符,所以写入时会出现乱序,在写入后加BufferedReader
;可以解决newLine()
Eg1.
需求:在硬盘上,创建一个文件并写入一些文字数据。找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
//调用write方法,将字符串写入到流中。
fw.write("abcde");
//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中。
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
fw.close();
}
}
Eg2.
/*
演示对已有文件的数据续写。
*/
import java.io.*;
class FileWriterDemo3
{
public static void main(String[] args) throws IOException
{
//传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。
FileWriter fw = new FileWriter("demo.txt",true);
fw.write("nihao\r\nxiexie");
fw.close();
}
}
Eg.3
//将C盘一个文本文件复制到D盘。
/*
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
*/
import java.io.*;
class CopyText
{
public static void main(String[] args) throws IOException
{
copy_2();
}
public static void copy_2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
fw = new FileWriter("SystemDemo_copy.txt");
fr = new FileReader("SystemDemo.java");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
if(fr!=null)
try
{
fr.close();
}
catch (IOException e)
{
}
if(fw!=null)
try
{
fw.close();
}
catch (IOException e)
{
}
}
}
//从C盘读一个字符,就往D盘写一个字符。
public static void copy_1()throws IOException
{
//创建目的地。
FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");
//与已有文件关联。
FileReader fr = new FileReader("RuntimeDemo.java");
int ch = 0;
while((ch=fr.read())!=-1)
{
fw.write(ch);
}
fw.close();
fr.close();
}
}
5. 装饰设计模式
5.1 什么情况下使用装饰设计模式
当我们需要对一个类的功能进行改进、增强的时候
5.2 装饰模式的基本格式。
- 含有被装饰类的引用
- 通过构造函数传入被装饰类对象
- 和被装饰类含有同样的方法,其中调用被装饰类的方法,对其进行改进、增强
- 和被装饰类继承同一个类或实现同一个接口,可以当做被装饰类来使用
5.3 了解BufferedReader、BufferedWriter的原理。
BufferedReader
、
BufferedWriter
都是装饰类,他们可以装饰一个
Reader
或
Writer
,给被装饰的Reader和Writer提供缓冲的功能。就像我们用
BufferedReader
、
BufferedWriter
装饰
FileReader
和
FileWriter
,使用的读写功能还是
FileReader
和
FileWriter
的,但给这两个类的读写添加了缓冲功能。
6 字节流
基本操作与字符流相同,字节流可以操作任意类型数据
6.1 自定义缓冲区读写
- 原理和字符流相同,都是为了提高效率
- 定义数组缓冲数据,一次读取一个数组,一次写出一个数组,减少操作文件的次数
6.2 BufferedInputStream、BufferedOutputStream
- 和
、BufferedReader
原理相同,都是包装类BufferedWriter
-
、BufferedInputStream
包装BufferedOutputStream
提供缓冲功能InputStream``和OutputStream
6.3 FileOutputStream
public class IoDemo03 {
public static void main(String[] args) {
FileOutputStream outputStream=null;
try {
//创建源
//选择流
outputStream = new FileOutputStream("test.txt",true);
//操作
String s="i love you hunan";
byte[] bytes=s.getBytes(); //字符==>字节 编码
outputStream.write(bytes,0,bytes.length);
FileInputStream inputStream = new FileInputStream("test02.txt");
byte[] bytes1=new byte[1024];
int read ;
while ((read=inputStream.read(bytes1))!=-1) {
String str=new String(bytes1,0,read); //字节==>字符 解码
System.out.print(str );
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.4 FileInputStream
public class IoDemo01 {
public static void main(String[] args) {
//1.确定源 file 或者 字节数组流
File file=new File("test.txt");
//System.out.println(file.getAbsolutePath());
//2.选择流
InputStream inputStream=null;
try {
inputStream=new FileInputStream(file);
//3.操作
int temp=0;
while((temp=inputStream.read())!=-1){
System.out.print((char) temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//4.释放资源
}
}
public class IoDemo02 {
public static void main(String[] args) {
//1.确定源
File file =new File("test.txt");
//2.选择流
FileInputStream inputStream=null;
try {
//3.操作
inputStream = new FileInputStream(file);
byte[] bytes = new byte[1024]; //缓冲区
int temp;
while((temp=inputStream.read(bytes))!=-1){
System.out.print(new String(bytes));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
//4.释放资源
}finally{
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
7. 转换流
字符流与字节流之间的桥梁,方便了字符流与字节流之间的操作,字节流中的数据都是字符时,转成字符流操作更高效
注:转换流的输入流和输出流都可以指定编码表,输出指定的编码,输入必须指定相同编码。
InputStreamReader
,
OutputStreamWriter
InputStreamReader
public static void main(String[] args) {
BufferedReader bufferedReader = null;
try {
// 1. 读取目标文件中的值
String fileName = "D:\\初级机试题\\房源库.txt";
bufferedReader = new BufferedReader(
new InputStreamReader(new BufferedInputStream(new FileInputStream(fileName)),"GBK"));
// 包装流读取一行数据
String s = bufferedReader.readLine();
System.out.println(s);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
OutputStreamWriter
public static void main(String[] args) {
BufferedWriter bufferedWriter = null;
try {
// 1. 读取目标文件中的值
String fileName = "D:\\初级机试题\\房源库.txt";
bufferedWriter = new BufferedWriter(
new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("Success.txt")), "UTF-8"));
bufferedWriter.write("世界你好 我喜欢你");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bufferedWriter !=null) {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
8. 标准输入,输出
System
类中的成员变量:
in
,
out
。
- 它们各代表了系统标准的输入和输出设备。
- 默认输入设备是键盘,输出设备是显示器。
- System.in的类型是InputStream.
- System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
9. 流操作小结
通过三个明确来完成。
1,明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer。
2,操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3,当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘。键盘
目的设备:内存,硬盘,控制台。
Eg.
1,将一个文本文件中数据存储到另一个文件中。复制文件。
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件。
是!这时就可以选择Reader
这样体系就明确了。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘。上一个文件。
Reader体系中可以操作文件的对象是 FileReader
是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件。
Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。
---------------------------------------
2,需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在。
那么分别分析
源:InputStream Reader
是不是纯文本?是!Reader
设备:键盘。对应的对象是System.in.
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
所以既然明确了Reader,那么就将System.in转换成Reader。
用了Reader体系中转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
**************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
但是FileWriter是使用的默认编码表。GBK.
但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter。
而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);
所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
需要用到转换流。