java.io.FIle类
文件或目录路径名的抽象表示形式.可以使用File类对文件或文件夹进行操作,比如:
创建一个新的文件/文件夹
删除文件/文件夹
获取文件/文件夹
判断文件/文件夹是否存在
对文件夹进行遍历
获取文件的大小
注: File类是一个与操作系统无关的类,任何操作系统都可以使用这个类中的方法.
I/O
java中的I/O操作主要是指java.io包下的内容,进行输入、输出操作.输入也叫做读取数据,指从磁盘文件中读取数据到内存中;输出也叫做写出数据.指将内存中的数据写入到磁盘文件上.
I/O的分类
根据数据的流向可以分为: 输入流和输出流
根据数据的类型可以分为: 字节流和字符流
字节流和字符流的超类
字节输入流的超类是InputStream,字节输出流的超类是OutputStream.
字符输入流的超类是Reader,字符输出流的超类是Writer.
一切皆为字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个一个的字节,那么传输的时候也是如此.字节流可以传输任意文件数据,在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终都是二进制字节数据.
文件存储的原理及文本编辑器打开文件的原理
写数据的时候会把传入的十进制的数据转换为二进制的数据.比如传入的十进制数据为97,转换为1100001,在文本编辑器打开文件时,会查询编码表,把字节转换为字符表示.二进制数据值位于0-127之间,会查询ASCII表,97则对应a.其他的值会查询系统默认编码表(中文系统则查询GBK编码表).
为什么字节流读取中文会乱码
因为字节流只能一个字节一个字节的从文件中读取,如果使用GBK编码的时候,一个中文字符占用2个字节;使用UTF-8编码时,一个中文字符占用3个字节.所以字节流只能读取一个汉字的一部分,从而导致乱码.
字节输出流OutputStream
java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地,它定义了字节输出流的基本性功能和方法.
// 关闭此输出流并释放与此流相关联的所有系统资源
public void close();
// 刷新此输出流并强制写出所有缓冲的输出字节
public void flush();
// 将b字节数组写入此输出流
public void write(byte[] b);
// 将指定byte数组中从偏移量off开始的len个字节写入到此输出流
public void write(byte[] b, int off, int len);
// 将指定的字节写入到此输出流
public abstract void write(int b);
write()方法所写的数据并没有直接传到输出流相连中的外设上,而是先暂时的存放在流的缓冲区中,等到缓冲区的数据积累到一定数量,再执行一次向外设的写操作把它们全部写到外设上.
字节输出流OutputStream的直接已知子类
// 往字节数组里面写数据的字节输出流
ByteArrayOutputStream
// 往文件中写数据的字节输出流
FileOutputStream
// 带过滤器的字节输出流
FilterOutStream
// 将对象转换为字节数据写入到文件中
ObjectOutputStream
OutputStream
// 通过管道传输数据
PipeOutputStream
输出流即写入数据到文件中的原理
java程序->JVM(Java虚拟机)->os(操作系统)->os调用写数据的方法->把数据写入到文件中.
字节输出流的使用步骤
/**
* 一次写一个字节
*/
public class DemoOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("1.txt");
// 这传输的是字节,写入到文件中是字母a
fos.write(97);
fos.close();
}
}
/**
* 一次写多个字节。
* 如果写的第一个字节是正数(0-127区间),那么显示的时候会查询ASCII表。
* 如果写的第一个字节是负数,那么第一个字节和第二个字节会组成一个中文显示,查询系统默认编码表(GBK)
*/
public class DemoOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("1.txt");
byte[] bytes = {65,66,67,68,69};
// 写入后打开文件结果显示ABCDE
fos.write(bytes);
fos.close();
}
}
/**
* 该方法使用即从off位置开始len个长度的字节写入文件中,比较简单
*/
public void write(byte[] b, int off, int len);
/**
* 上面使用的默认构造函数是覆盖写文件
* 追加写文件,使用FileOutPutStream两个参数的构造方法即可
* boolean值为true,表示在文件末尾追加数据
* boolean值为false,表示覆盖写文件
*/
FileOutPutStream(String name, boolean append);
字节输入流InputStream
此抽象类表示字节输入流的所有类的超类.定义了所有子类共性的方法.
// 从输入流中读取数据的下一个字节
int read()
// 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
int read(byte[] b)
// 关闭此输入流并释放与该流关联的所有系统资源
void close()
FileInputStream文件字节输入流
构造函数中可以传入文件File类型的文件对象,也可以传入文件路径
FileInputStream(String name)
FileInputStream(File file)
读取数据的原理(硬盘->内存)
java程序->JVM->OS->OS调用读取数据的方法->读取文件
字节输入流的使用步骤
FileInputStream的使用代码
/**
* read()
* 一次读取一个字节
*/
public class DemoInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("1.txt");
// 记录读取的字节
int result = 0;
// read()方法参数为空的话一次读取一个字节,返回-1说明文件为空
while((result = fileInputStream.read()) != -1){
System.out.println(result);
}
fileInputStream.close();
}
}
/**
* read(bytes[])
* 一次读取多个字节
*/
public class DemoInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("1.txt");
byte[] bytes = new byte[1024];
int length = 0;
while((length = fileInputStream.read(bytes))!= -1){
// 将字节转换为字符串,截取字节数组[0:length]部分
// 因为read(byte[])方法是从文件中读取byte.length大小的字节放入字节数组中
// 当读取最后的文件内容时,如果不够byte.length大小的字节,只替换byte数组的前面部分,后面还是保留上一次读取的部分,导致取到错误内容
// 所以使用String的构造方法截取需要的部分
System.out.println(new String(bytes, 0, length));
}
fileInputStream.close();
}
}
字节流读取文本文件时的问题
一个中文字符可能占用多个字节存储,比如使用GBK编码的时候,一个中文字符占用2个字节;使用UTF-8编码时,一个中文字符占用3个字节.所以当使用字节流读取文本文件时,遇到中文字符时,可能不会显示完整的字符,导致乱码.
Reader字符输入流
是字符输入流的最顶层父类,定义了一些共性的成员方法,是一个抽象类.
Reader共性的成员方法有
// 读取单个字符并返回
int read();
// 一次性读取多个字符,将字符读入数组
int read(char[] chars);
// 关闭该流并释放与之关联的所有资源
void close();
Reader的直接已知子类
// 带缓冲的reader
BufferedReader
// 读取字符数组的reader
CharArrayReader
// 带过滤器的reader
FilterReader
// 字节流向字符流转换的转换流reader
InputStreamReader
// 管道流reader
PipeReader
// 读取字符串的流reader
StringReader
FileReader: InputStreamReader的子类
把硬盘文件中的数据以字符的方式读取到内存中.此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的.要自己指定这些值,可以先在FileInputStream上构造一个InputStreamReader.
String encoding = "GBK";
// 文件字节输入流转成字符输入流(inputStreamReader用于字节流向字符流转换)
InputStreamReader inputStreamReader = new InputStreamReader(
new FileInputStream(file), encoding);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
FileReader的使用
// 一次读取一个字符
public class DemoReader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("1.txt");
int len = 0;
while((len = fr.read()) != -1){
System.out.println((char)len);
}
fr.close();
}
}
// 一次读取多个字符
public class DemoReader {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("1.txt");
char[] cs = new char[1024];
int len = 0;
while((len = fileReader.read(cs))!= -1){
System.out.println(new String(cs, 0, len));
}
fileReader.close();
}
}
Writer: 字符输出流
FileWriter: OutStreamWriter的子类
作用: 将内存中的字符数据写入到文件中.
FileWriter字符输出流的使用步骤
创建FileWriter对象,构造方法中绑定要写入数据的目的地
使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
使用FileWriter中的方法flush,把内存缓冲区中的数据刷新到文件中(刷新完还可以继续write,close就不能继续write了)
释放资源(也会把内存缓冲区中的数据刷新到文件中)
FileWriter的使用
public class DemoFileWriter {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("1.txt");
fw.write("97");
// fw.flush();
fw.close();
}
}
public class DemoBufferedOutputStream {
public static void main(String[] args) throws FileNotFoundException {
// 文件字节输出流,用于将字节数据存入文件中
FileOutputStream fileOutputStream = new FileOutputStream("1.txt");
// 缓冲字节输出流,提高FileOutputStream的效率
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
try {
bufferedOutputStream.write("测试".getBytes());
bufferedOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
// 缓冲流关闭会自动把字节流关闭
bufferedOutputStream.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
}
BufferedInputStream的使用与BufferedOutputStream类似import java.io.*;
public class DemoBufferedWriter {
public static void main(String[] args){
// 文件字符输入流
FileReader fileReader = null;
// 文件字符输出流
FileWriter fileWriter = null;
// 缓冲字符输入流
BufferedReader bufferedReader = null;
// 缓冲字符输出流
BufferedWriter bufferedWriter = null;
try {
fileReader = new FileReader("1.txt");
fileWriter = new FileWriter("2.txt");
// 使用BufferedReader缓冲输入流提高FileReader效率
bufferedReader = new BufferedReader(fileReader);
bufferedWriter = new BufferedWriter(fileWriter);
String line = null;
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
bufferedWriter.write(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
bufferedReader.close();
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class DemoOutputStreamWriter {
public static void main(String[] args) throws IOException {
// OutputStreamWriter将字符输出流转换为字节输出流。第一个参数为字节输出流OutputStream对象
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("1.txt"), "GBK");
outputStreamWriter.write("你好");
outputStreamWriter.flush();
outputStreamWriter.close();
}
}
创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
使用InputStreamReader对象的read方法读取文件
释放资源
注: 构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
InputStreamReader使用
public class DemoInputStreamReader {
public static void main(String[] args) {
InputStreamReader inputStreamReader = null;
FileInputStream fileInputStream = null;
String line = null;
BufferedReader bufferedReader = null;
try {
// 创建字节输入流
fileInputStream = new FileInputStream("1.txt");
// 将字节输入流转换为字符输入流,并设置编码
inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
// 使用缓冲字符输入流对InputStreamReader加速
bufferedReader = new BufferedReader(inputStreamReader);
while((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}