File类
操作文件和文件夹java.io.File
File的构造方法:File f = new File("d:\note\test.txt")
路径可以是绝对/相对,文件/文件夹,存在/不存在
常用方法:
f.getAbsolutePath()
f.length()
f.exists()
f.isDirectory()
f.makdir()
f.createNewFile()
File[] list = f.listFiles()
IO
分类:
- 按照数据流向:输入流、输出流;
- 按照数据类型:字节流、字符流。
所以有:
- 字节输入流
InputStream
- 字节输出流
OutputStream
- 字符输入流
Reader
- 字符输出流
Writer
字节字符区别:
- 一切文件都是二进制保存,所有都可以用字节流。
- 汉字等占用多个字节(utf-8占2-4个字节),所以需要用字符流,专门处理文本问题,其他格式不行(图片、视频等)。
FileOutputStream
把内存中的数据写入到硬盘中,三步:
- 创建对象
FileOutputStream fos = new FileOutputStream(文件名);
(如果没有文件,会创建) - 调用write方法,写入内容
fos.write(byte[]);
- 释放资源
fos.close();
数据追加需要用构造方法:new FileOutputStream(文件名, append: true);
换行,windows是
FileInputStream
从硬盘读数据,三步:
- 创建对象
FileInputStream fis = new FileInputStream(文件名);
(如果没有文件,会报错) - 读数据
len = fis.read(byte[] b);
(读取b长度字节,文件末尾返回长度-1) - 释放资源
fis.close();
例子:复制一个图片
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream input = new FileInputStream("d:\test.jpg");
FileOutputStream output = new FileOutputStream("test_copy.jpg");
byte[] b = new byte[1024];
int len;
while ((len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.close();
input.close();
}
}
FileReader
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("f:\test.txt");
char[] ch = new char[1024];
int len = 0;
while ((len = fr.read(ch)) != -1) {
System.out.print(new String(ch, 0, len));
}
fr.close();
}
FileWriter
字符输出流使用步骤:
- 创建对象,绑定数据写入地址;
- 使用writer方法,写入到内存缓冲区中(字符转字节);
- 使用flush方法,把缓冲区中的数据写入到文件中;
- 释放资源。(把缓冲区中的数据写入文件中)
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("f:\test.txt");
fw.write("Hello World!!!");
fw.flush();
fw.write("--程序员");
fw.close();
}
IO异常
IO异常需要处理,JDK1.7前建议使用try-catch{},JDK1.7优化了try-with-resourse
语句,该语句保证了资源在语句结束时关闭。
public static void main(String[] args) {
try (FileWriter fw = new FileWriter("f:\test.txt")) {
fw.write("Hello World!!!");
} catch (IOException e) {
e.printStackTrace();
}
}
JDK9中try-with-resourse
引入了对象,但是没有JDK1.7方便。
缓冲流
之前都是单字节传递:流[byte] <-> JVM[byte] <-> OS[byte] <-> 硬盘[byte]
缓冲流可以多个数据传递:流[buffer] <> JVM[buffer] <> OS[buffer] <> 硬盘[buffer]
字节缓冲流
public class Test {
public static void main(String[] args) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("f:\test.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("f:\test_copy.txt"));) {
int len;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符缓冲流
字符缓冲流特有的方法:
BufferedReader
:public String readLine();
读取一行文字;BufferedWriter
:public void newLine();
写换行符。
import java.io.*;
public class Test {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("f:\test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
转换流
计算机底层是二进制存储,但是显示的是字符,这中间有一套转换规则:字符编码。
字符编码:ASCII、GBK(GB2312简体中文编码,GBK)、Unicode(utf-8, utf-16, utf-32)
windows默认编码GBK
编码,但是编辑器常用utf-8
编码,当读取windows系统创建的文件时,就会出现乱码。
如何读取呢?用转换流:读底层的字节流,中间按照指定编码方式转换成字符流。
InputStreamReader(new FileStream("f:\text"), "GBK")
按照GBK字符集解码成字符流OutputStreamWriter(new FileStream("f:\copy"), "GBK")
按照GBK字符集编码成字节流
例子:先在windows上创建一个文件,按照GBK读取,复制成UTF-8。
public static void main(String[] args) throws IOException {
InputStreamReader r = new InputStreamReader(new FileInputStream("f:\test.txt"), "GBK");
OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream("f:\copy.txt"));
int len;
char[] charArr = new char[1024];
while ((len = r.read(charArr)) != -1) {
w.write(charArr, 0, len);
}
w.close();
r.close();
}
序列化流
将对象以流的方式写入到文件中保存(字节),叫对象的序列化,反之叫反序列化。
注意:在序列化/反序列化时,被序列化的类需要实现java.io.Serializable
接口以启动序列化功能。
- 实现类
class Person implements Serializable {
public String name;
public transient int age; // transient修饰的成员不能被序列化
}
- 序列化:
writeObject()
public static void main(String[] args) {
Person p = new Person();
p.name = "张三";
p.age = 18;
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\test.txt"));
oos.writeObject(p);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- 反序列化:
readObject()
public static void main(String[] args) {
Person p;
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("f:\test.txt"));
p = (Person) in.readObject();
in.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return;
}
System.out.println(p.name);
}
打印流
print
和pintln
都是来自java.io.PrintStream
类,该类可以方便打印各种数据。
特点:
- 只负责数据输出,不负责数据读取
- 打印流不会抛出
IOException
- 有特有的方法
print
和println
构造方法:PrintStream(fileName)
,这里的filename指的是输出流的流向。
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream("f:\test.txt");
ps.write(97); // 写入a
ps.println(98); // 写入98
ps.close();
}
同样,System.out
就是PrintStream
类型的,它的流向是控制台。