Java I/O基础
流的概念
Stream:流
-
流入与流出以内存为参照
-
内存---->存储设备:流出(output)
-
存储设备---->内存:流入(input)
-
-
流指的是通道
流的分类
按方向:
-
输入流(InputStream)
-
输出流(OutputStream)
按单位:
-
字节流:以字节(Byte, FF)为单位, 可读写所有数据(包括图片,音频,所有格式数据)
-
字符流:以字符(char, FFFF)为单位, 只能读写文本数据
按功能:
-
节点流:具有实际传输数据的读写功能
-
过滤流:在节点流的基础上的增强功能
字节流
字节流抽象类
InputStream:字节输入流
OutputStream:字节输出流
文件字节流
java.io.FileInputStream 和 java.io.FileOutputStream
字节流的读取单位是Byte,参照ASCII码表。(即每调用一次read只读取一个字节)
read返回值为其读取的数据,到达文件末尾时,返回值为-1
FileInputStream的使用
读取中文,sout时会乱码
若自写缓冲区小于3Byte仍会乱码
-
创建FileInputStream对象
-
读取文件
-
关闭
// 1.创建FileInputStream,将fis与文件建立连接
FileInputStream fis = new FileInputStream("d:\\aaa.txt");
// 2.读取文件(数据)
System.out.println(fis.read()); // 读取单个Byte(字节)
// 2.1 读一个打印
int data = 0;
while ((data=fis.read())!=-1) {
System.out.print((char)data); // 转换为char类型
}
// 2.2 读取到数组(缓冲区)中再打印
byte[] buf = new byte[3];
int count = 0;
while ((count=fis.read(buf))!=-1) {
System.out.println(new String(buf,0,count)); // [,)
}
// fis.read(buf); // fis.read(buf)将fis的文件读入buf,返回值是读入缓冲区(buf)的总字节数
// new String(buf); // 构造一个String对象,将数组传入该对象
// 3.关闭
fis.close();
FileOutputStream的使用
-
创建FileOutputStream对象
-
写入文件(数据)
-
关闭
new FileOutputStream会新创一个文件
// 1.创建文件字节输出流对象
FileOutputStream fos = new FileOutputStream("d:\\bbb.txt",true); // 默认false,false时写操作会覆盖(append开关)
// 2.写入文件
fos.write(97); // 写入时会转成 'a',使用的unicode编码
fos.write('97')
fos.write('b');
fos.write('c');
String str = "helloworld";
fos.write(str.getBytes()); // getBytes()方法,返回值是byte数组,使用平台默认编码
// 3.关闭
fos.close();
文件字节流复制文件
// 1.创建流
// 1.1文件输入流
FileInputStream fis = new FileInputStream("d:\\30.jpg");
// 1.2文件输出流
FileOutputStream fos = new FileOutputStream("d:\\copy1.jpg");
// 2. 边读边复制
byte[] buf = new byte[1024];
int count = 0;
while ((count=fis.read(buf))!=-1) {
fos.write(buf,0,count);
}
// 3. 关闭
fis.close();
fos.close();
字节缓冲流(过滤流)
java.io.BufferedInputStream / java.io.BufferedOutputStream
- 需要传入文件字节流
- 自带缓冲区(buf)
BufferedInputStream的使用
使用字节缓冲流,读取中文sout时仍会乱码
若自写缓冲区,则可正常sout中文
-
创建FileInputStream对象,再传入前者创建BufferedInputStream对象
-
读取
-
关闭
// 1. 创建
FileInputStream fis = new FileInputStream("d:\\aaa.txt");
// 传入字节流,创建BufferedInputStream,用来增强字节流
BufferedInputStream bis = new BufferedInputStream(fis);
// 2.1 读取
int data = 0;
// 直接从内置缓冲区(buf)读取,buf大小默认8kb。
while ((data=bis.read())!=-1) {
System.out.print((char)data);
}
// 2.2 可以读取中文,2.1不行
byte[] buf = new byte[1024];
int count = 0;
while ((count=bis.read(buf))!=-1) {
System.out.print(new String(buf,0,count));
}
// 3. 关闭(内置关闭fis的方法)
bis.close();
BufferedOutputStream的使用
-
创建流(类似BufferedInputStream)
-
写入文件
-
关闭
// 1.创建字节输出缓冲流
FileOutputStream fos = new FileOutputStream("d:\\buffer.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 2.写入文件
for (int i=0; i<10; i++) {
bos.write("helloWorld\n".getBytes()); // 写入8k缓冲区
bos.flush(); // 刷新到硬盘(从内存冲刷到硬盘)
}
// 3. 关闭(内部调用flush方法)
bos.close();
对象流
java.io.ObjectOutputStream / java.io.ObjectInputStream
增强了缓冲区功能
增强了8种数据类型和字符串功能(write方法可传入的类型增多)
增强了读写对象的功能
被序列化的Student类
-
序列化对象要实现Serializable接口
-
序列化类中属性(类)要求实现Serializable接口
-
serialVersionUID:序列化版本号ID,保证序列化和反序列化的类是同一个类,会有个默认值
-
使用transient(短暂的)修饰属性,该属性不能被序列化
-
static属性也不能被序列化
-
序列化多个对象可以借助集合来实现
public class Student implements Serializable {
private static final long serialVersionUID = 100L;
private String name;
private transient int age;
private static String county;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
ObjectOutputStream的使用
-
创建
-
序列化(写操作)
-
关闭
// 1. 创建对象流(代理)
FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 2. 序列化(写操作)
// 首先创建Object
Student s1 = new Student("zhangsan", 18);
Student s2 = new Student("lisi", 20);
// 2.1单个序列化
oos.writeObject(s1);
// 2.2批量序列化
// 将两个对象放入ArrayList当中,以实现批量序列化
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
oos.writeObject(list);
// 3. 关闭
oos.close();
ObjectInputStream的使用
-
创建对象流
-
读取文件
-
关闭
readObject方法返回的是一个readObject对象
// 1.创建一个对象流
FileInputStream fis = new FileInputStream("d:\\stu.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
// 2.1 读取文件(反序列化)
Student s = (Student)ois.readObject(); // 强制转换成Student对象
// 2.2 批量反序列化
ArrayList<Student> list = (ArrayList<Student>)ois.readObject(); // 强制转换成ArrayList<>对象
// 3.关闭
ois.close();
System.out.println(s.toString());
System.out.println(list.toString());
编码方式
字符编码:
编码与解码方式不一致时,会出现乱码
ANSI编码,代表国家或地区当地的编码方式,中国ANSI即为GBK
- ISO-8859-1:1字节,ASCII升级版,使用了首位
- UTF-8:可变长度1~3字节,使用Unicode码表
- GB2312:1~2字节,简中
- GBK:1~2字节,国标扩
- BIG5 台湾:繁中
字符流
字符流抽象类
Reader:字符输出流
Writer:字符输入流
文件字符流
FileReader的使用
-
创建流
-
读取
-
关闭
java.io.FileReader
1 char = 2 byte = 16 bit
字符 字节 位
read方法, 返回值是byte(字节)还是char(字符)取决于类 --> 多态
FileReader read方法返回的是字符数(char)
FileInputStream read方法返回的是字节数(byte)
// 1. 创建FileReader流 文件字符输入流
FileReader fr = new FileReader("d:\\hello.txt");
// 2. 读取
// 2.1 单个字符读取
// int data = 0;
// while ((data=fr.read())!=-1) {
// System.out.println((Integer.toHexString(data))); 转换成16进制
// }
// 2.2 多个字符
char[] buf = new char[2]; // 通常设置为1024
int count = 0;
while ((count=fr.read(buf))!=-1) {
System.out.println(new String(buf, 0, count));
}
// 3.关闭
fr.close();
FileWriter的使用
java.io.FileWriter
- read方法可传参类型:char,char[],String
- append方法,可追加写入
// 1.创建一个FileWriter对象
FileWriter fw = new FileWriter("d:\\fileWriter.txt");
// 2. 写入
for (int i = 0; i < 10; i++) {
fw.write("这是字符输入流" + i + "\n");
fw.flush();
}
// 3. 关闭
fw.close();
文件字符流复制文件
- 使用FileReader和FileWriter复制文本文件, 不能复制图片或二进制文件
- 读入内存时(即read时)会将图片二进制文件先转成字符编码
// 1. 创建写流和读流
FileReader fr = new FileReader("d:\\fileWriter.txt");
FileWriter fw = new FileWriter("d:\\fileWriter.copy.txt");
// 2. 复制
// 加缓冲区,效果一致
// char[] buf = new char[1024];
// int count = 0;
// while ((count=fr.read(buf))!=-1) {
// fw.write(buf,0,count);
// }
int data = 0;
while ((data=fr.read())!=-1) {
fw.write(data);
}
// 关闭
fw.close();
fr.close();
字符缓冲流(过滤流)
字符缓冲流:BufferedReader / BufferdWriter
高效读写
支持输入换行符
可一次写一行, 读一行
BufferdReader的使用
readline方法,读取一行
// 1. 创建缓冲流
FileReader fr = new FileReader("d:\\fileWriter.txt");
BufferedReader br = new BufferedReader(fr);
// 2. 读取
// 2.1 第一种方式
// char[] buf = new char[1024];
// int count = 0;
// while ((count=br.read(buf))!=-1) {
// System.out.print(new String(buf,0,count));
// }
// 2.2 第二种方式
String line = null;
while ((line=br.readLine())!=null) { //读一行文字。 一行被视为由换行符('\ n'),回车符('\ r')中的任何一个或随后的换行符终止
System.out.println(line);
}
// 3. 关闭
br.close();
BufferedWriter的使用
newLine方法:写入一个换行符,Linux \r,windows \n \r
// 1. 创建BufferedWriter对象
FileWriter fw = new FileWriter("d:\\bufWriter.txt");
BufferedWriter bw = new BufferedWriter(fw);
// 2.写入
for (int i = 0; i < 10; i++) {
bw.write("这是缓冲字符流输入" + i);
bw.newLine();
bw.flush();
}
// 3. 关闭
bw.close();
打印流
java.io.PrintWriter
不会进行转换,写入97,文本内显示是97
// 1. 创建打印流
PrintWriter pw = new PrintWriter("d:\\print.txt");
// 2. 打印
pw.println(97);
pw.println(true);
pw.println(3.14);
pw.println('a');
// 3. 关闭
pw.close();
转换流
java.io.InputStreamReader / java.io.OutputStreamWriter
- 字节流与字符流的相互转换
- 可设置字符编码方式
InputSreamReader的使用
// 1. 创建InputStreamReader对象
FileInputStream fis = new FileInputStream("d:\\fileWriter.txt");
InputStreamReader isr = new InputStreamReader(fis, "gbk"); // 解码方式
// 2. 读取文件
int data = 0;
while ((data = isr.read()) != -1) {
System.out.println((char)data);
}
// 3. 关闭
isr.close();
OutputStreamWriter的使用
// 1. 创建OutputStreamWriter
FileOutputStream fos = new FileOutputStream("d:\\oaw.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk"); // 写入的编码格式
// 2. 写入
for (int i = 0; i < 10; i++) {
osw.write("OutputStreamWriter转换流" + i + "\n");
osw.flush();
}
// 3.关闭
osw.close();
File类
表示文件或文件夹的路径
分隔符
File.pathSeparator // ;
File.separator // \
文件操作
创建文件 :File file = new File(name)
删除文件:file.delete()
获取文件信息
判断
// 1. 创建文件
File file = new File("d:\\fileOpe\\file.txt");
// System.out.println(file.toString());
if (!file.exists()) {
boolean b = file.createNewFile();
System.out.println("创建结果:" + b);
}
// 2. 删除文件
// 2.1 直接删除
//System.out.println("删除结果:" + file.delete());
// 2.2 使用jvm退出时删除
//file.deleteOnExit();
//Thread.sleep(5000);
// 3. 获取文件信息
System.out.println("获取文件的绝对路径:" + file.getAbsolutePath());
System.out.println("获取路径:" + file.getPath()); // 创建时是什么路径就是什么路径
System.out.println("获取文件名称:" + file.getName());
System.out.println("获取父目录:" + file.getParent());
System.out.println("获取文件长度:" + file.length());
System.out.println("文件创建时间:" + new Date(file.lastModified()).toLocaleString());
// 4. 判断 erw
System.out.println("是否可写:" + file.canWrite());
System.out.println("是否是文件:" + file.isFile());
System.out.println("是否隐藏:" + file.isHidden());
文件夹操作
创建文件夹 :File dir = new File(name) ; dir.mkdirs();
删除文件夹:dir.delete() 删除时,只删除最底层的空目录
获取文件信息
判断
遍历: list返回的是String类,listFile返回的是File类
// 1. 创建文件夹
File dir = new File("d:\\aaa\\bbb\\ccc");
// System.out.println(dir.toString());
if (!dir.exists()) {
//dir.mkdir(); // 只能创建单级目录
System.out.println("创建结果:" + dir.mkdirs());
}
// 2. 删除文件夹
// 2.1 直接删除
//System.out.println("删除的结果是" + dir.delete());
// 2.2 使用jvm删除
//dir.deleteOnExit(); // 删除效果同2.1
//Thread.sleep(5000);
// 3. 获取文件夹信息
System.out.println("获取绝对路径:" + dir.getAbsolutePath());
System.out.println("获取路径:" + dir.getPath());
System.out.println("获取文件夹名称:" + dir.getName());
System.out.println("获取父目录:" + dir.getParent());
System.out.println("获取创建时间:" + new Date(dir.lastModified()).toLocaleString());
// 4. 判断
System.out.println("是否是文件夹" + dir.isDirectory());
System.out.println("是否隐藏" + dir.isHidden());
// 5. 遍历
File dir2 = new File("d:\\");
// list方法,将文件夹传入数组
String[] files = dir2.list();
for (String str : files) {
System.out.println(str);
}
FileFilter的使用
类似linux的管道
// 创建文件类
File dir2 = new File("d:\\");
// 匿名内部类
File[] file2 = dir2.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
// 判断文件是否以.jpg结尾
if (pathname.getName().endsWith(".jpg")) {
return true; // 表示accept(即过滤成功)
}
return false; // 表示过滤失败
}
});
for (File file : file2) {
System.out.println(file);
}
递归遍历
public static void listDir(File dir) {
// 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件(或文件夹)
File[] f1 = dir.listFiles();
// 输出dir的绝对路径
System.out.println(dir.getAbsoluteFile());
// f1数组不为null且 f1数组的长度>0
// != null表示MyFile存在, length>0表示MyFile文件夹内有文件(或文件夹)
if (f1 != null && f1.length > 0) {
// 开始遍历
for (File file : f1) {
// 判断是否为文件夹
if (file.isDirectory()) {
// 递归调用listDir,传入file
listDir(file);
} else {
System.out.println(file.getAbsolutePath());
}
}
}
}
递归删除
因为删除目录(文件夹)时,只删除最底层的空目录,故需使用递归删除
public static void deleteDir(File dir) {
File[] f1 = dir.listFiles();
if (f1 != null && f1.length > 0) {
for(File file : f1) {
if (file.isDirectory()) {
deleteDir(file);
} else {
// 删除文件
System.out.println("删除" + file.getAbsoluteFile() + "结果:" + file.delete());
}
}
}
// 删除 dir(可能为目录)
System.out.println("删除" + dir.getAbsoluteFile() + "结果:" + dir.delete());
}
Properties
和流有关的方法
list(PrintStream out)方法:将此属性列表打印到指定的输出流
store方法:通过fos实现
load方法:通过fis实现
// 1. 创建集合
Properties properties = new Properties();
// 2. 添加数据
properties.setProperty("usrName", "张三");
properties.setProperty("age", "20");
// ====list方法====
PrintWriter pw = new PrintWriter("d:\\PropertiesPrint.txt");
properties.list(pw);
pw.close();
// ====store方法====(保存)
FileOutputStream fos = new FileOutputStream("d:\\store.properties");
// 调用 store方法,通过fos实现,进行保存
properties.store(fos,"comments");
fos.close();
// ====load方法====(加载)用的较多
Properties properties2 = new Properties();
FileInputStream fis = new FileInputStream("d:\\store.properties");
// 加载前
System.out.println(properties2.toString());
// 加载
properties2.load(fis);
// 加载后
System.out.println(properties2.toString());
// 关闭
fis.close();