概念:内存与存储设备之间传输数据的通道。
按方向【重点】 :
按处理单位:
按功能:
字节流的父类(抽象类)
FileInputStream
代码演示:
public class TestFileInputStream {
public static void main(String[] args) throws IOException {
//1 创建对象, 指定文件位置
FileInputStream fis = new FileInputStream("e:\\javaee2308.txt");
//2 读取
int s1,s2;
//2.1 单个字节读取
/*s1 = fis.read();
System.out.println((char) s1);
while ((s2=fis.read())!=-1) {
System.out.println((char) s2);
}*/
//2.2 多个字节读取
byte[] bytes = new byte[1024 * 4];
int len;
while ((len=fis.read(bytes))!=-1) {
System.out.println(new String(bytes,0,len));
}
//3 关闭流
fis.close();
}
}
FileOutputStream
代码演示:
public class TestFileOutputStream {
public static void main(String[] args) throws Exception{
//1 创建对象, 指定文件的位置
//如果文件不存在, 则自动创建, 如果文件存在, 默认覆盖内容, 可设置追加方式
FileOutputStream fos = new FileOutputStream("e:\\aaa.txt");
//2 写入 换行转义符: Win: \r\n; Linux: \n; Mac: \r;
String s = "Hello World\r\n";
for (int i = 0; i < 10; i++) {
fos.write(s.getBytes());
}
//3 关闭
fos.close();
System.out.println("写入成功");
}
}
缓冲流:BufferedOutputStream/BufferedInputStream
代码演示:
BufferedInputStream:
public class TestBufferInputStream {
public static void main(String[] args) throws Exception {
//1 创建字节缓冲流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\javaee2308.txt"));
//2 读取
int d;
while ((d= bis.read())!=-1) {
System.out.println((char) d);
}
//3 关闭(关闭缓冲流时,会自动关闭字节流)
bis.close();
}
}
BufferedOutputStream:
public class TestBufferOutputStream {
public static void main(String[] args) throws Exception{
//1 创建字节缓冲流
// BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\ccc.txt"));
BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get("e:\\ccc.txt")));
//2 写入
String s = "HelloWorld";
for (int i = 0; i < 10; i++) {
bos.write(s.getBytes()); //写入缓冲区
}
//3 刷新缓冲区
bos.flush();
//4 关闭缓冲流(如果缓冲区中有数据会自动刷新)
bos.close();
}
}
课堂案例
使用字节流实现复制图片
代码演示:
public class CopyFile {
public static void main(String[] args) throws Exception{
//1 创建
BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(Paths.get("D:\\Users\\胡昊龙\\Pictures\\美图\\微信图片_20240116191011.jpg"))
);
BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get("e:\\copy.jpg")));
//2 读取 和 写入
byte[] bytes = new byte[1024 * 8];
int len;
while ((len= bis.read(bytes))!=-1) {
bos.write(bytes,0,len);
bos.flush();
}
//3 关闭
bis.close();
bos.close();
System.out.println("复制成功");
}
}
对象流:ObjectOutputStream/ObjectInputStream
使用流传输对象的过程称为序列化、反序列化。
对象序列化的细节:
- 序列化类及其对象属性必须实现Serializable接口。
- transient修饰为临时属性不参与序列化,静态属性也不参与序列化。
- 读取到文件尾部的标志:java.io.EOFException。
- 使用serialVersionUID属性保证序列化的类和反序列化的类是同一个类。
代码演示:
ObjectOutputStream:
public class TestObjectOutputStream {
public static void main(String[] args) throws Exception{
//序列化
Student stu = new Student("张三", 20);
//1 创建
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("e:\\张三.bin")));
//2 写入
oos.writeObject(stu);
//3 刷新
oos.flush();
//4 关闭
oos.close();
System.out.println("序列化完成");
}
/**
* 标记接口 Serializable 序列化接口
* 静态内部类 Student对象
*/
static class Student implements Serializable {
代码块...
}
}
ObjectInputStream:
public class TestObjectInputStream {
public static void main(String[] args) throws Exception{
//反序列化
//1 创建
ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get("e:\\张三.bin")));
//2 读取
TestObjectOutputStream.Student student = (TestObjectOutputStream.Student) ois.readObject();
System.out.println(student.toString());
//3 关闭
ois.close();
System.out.println("反序列化完成");
}
}
思考
文本文件和图片、音频、视频文件在硬盘中有区别吗?
- 本质上没有区别,都是二进制数据。
- 文本文件有字符编码。
文件的后缀名作用?修改后缀名是否会改变文件内容?
- 后缀名的作用:标识文件的类型,从而决定使用什么软件打开文件。
- 修改后缀名不会改变文件内容。
字符编码: 当编码方式和解码方式不一致时,会出现乱码。
名称 | 说明 |
---|---|
ISO-8859-1 | 收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。 |
UTF-8 | 针对Unicode的可变长度字符编码 |
GB2312 | 简体中文 |
GBK | 简体中文、扩充 |
BIG5 | 台湾,繁体中文 |
字符流的父类(抽象类)
Reader:字符输入流
public int read(){}
public int read(char[] c){}
public int read(char[] b,int off,int len){}
Writer:字符输出流
public void write(int n){}
public void write(String str){}
public void write(char[] c){}
FileWriter
代码演示:
public class TestFileWriter {
public static void main(String[] args) throws Exception {
//1 创建文件字符流
FileWriter fw = new FileWriter("e:\\aaa.txt");
//2 写入
for (int i = 0; i < 10; i++) {
fw.write("好好学习, 天天向上\r\n");
}
//3 刷新
fw.flush();
//4 关闭
fw.close();
System.out.println("写入完成");
}
}
FileReader
代码演示:
public class TestFilerReader {
public static void main(String[] args) throws Exception{
//1 创建文件字符流
FileReader fr = new FileReader("e:\\aaa.txt");
//2 读取
char[] chars = new char[1024 * 4];
int len;
while ((len=fr.read(chars))!=-1) {
System.out.println(new String(chars,0,len));
}
//3 关闭
fr.close();
}
}
桥转换流:InputStreamReader/OutputStreamWriter
代码演示:
InputStreamReader
public class TestInputStreamReader {
public static void main(String[] args) throws Exception{
//1 创建
InputStreamReader isr = new InputStreamReader(Files.newInputStream(Paths.get("e:\\ddd.txt")), "GBk");
//2 读取
char[] chars = new char[1024 * 4];
int len;
while ((len=isr.read(chars))!=-1) {
System.out.println(new String(chars,0,len));
}
//3 关闭
isr.close();
System.out.println("读取成功...");
}
}
OutputStreamWriter
public class TestOutputStreamWriter {
public static void main(String[] args) throws Exception{
//1 创建
OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(Paths.get("e:\\ddd.txt")),"GBK");
//2 写入
for (int i = 0; i < 10; i++) {
osw.write("好好学习,天天向上\r\n");
}
//3 刷新
osw.flush();
//4 关闭
osw.close();
System.out.println("写入成功...");
}
}
缓冲流:BufferedWriter/BufferedReader
BufferedWriter
public class TestBufferWriter {
public static void main(String[] args) throws Exception{
//1 创建
BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\BBB.txt"));
//2 写入
for (int i = 0; i < 10; i++) {
bw.write("好好学习,天天向上");
bw.newLine();
}
//3 刷新
bw.flush();
//4 关闭
bw.close();
}
}
BufferedReader
public class TestBufferReader {
public static void main(String[] args) throws Exception{
//1 创建
BufferedReader br = new BufferedReader(new FileReader("e:\\BBB.txt"));
//2 读取
String data;
while ((data=br.readLine())!=null) {
System.out.println(data);
}
//3 关闭
br.close();
}
}
打印流:把数据原样打印。
代码演示
PrintStream
public class PrintStream {
public static void main(String[] args) throws Exception {
//1 创建
PrintWriter ps = new PrintWriter("e:\\ppp.txt");
//2 打印
ps.println(97);
ps.println(true);
ps.println(3.12412446);
ps.println("Hello World");
//3 刷新
ps.flush();
//4 关闭
ps.close();
}
}
System.out
public class TestSystemOut {
public static void main(String[] args) throws Exception{
System.out.println("helloworld");//控制台输出"helloworld"
//重定向标准输出流
System.setOut(new PrintStream("d:\\console.txt"));
System.out.println("helloworld");
}
}
System.in
public class TestSystemIn {
public static void main(String[] args) throws Exception{
//Scanner input=new Scanner(System.in);
//字节输入流InputStream
//1 读取一个字节
// int d= System.in.read();
// System.out.println((char)d);
//2 读取一个字符
// InputStreamReader isr=new InputStreamReader(System.in);
// int d=isr.read();
// System.out.println((char)d);
//3 读取一行
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String d = br.readLine();
System.out.println(d);
}
}
RandomAccessFile即可以读取文件内容,也可以向文件中写入内容。
但是和其他输入/输入流不同的是,程序可以直接跳到文件的任意位置来读写数据。
读写模式 r:只读 rw:读写
作用: 快速定位数据,支持并发读写 方便的操作二进制文件
代码演示:
public class TestRandomAccessFile {
public static void main(String[] args) throws Exception{
write();
read();
}
//写入文件
public static void write() throws Exception{
//1 创建RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile("d:\\random.txt","rw");
//2 写入(把内存的二进制数据写入硬盘)
raf.writeUTF("张三");//2+6
raf.writeInt(20); //4个字节
raf.writeDouble(180.5);//8个字节
raf.writeBoolean(true);//1个字节
raf.writeUTF("李四");//2+6
raf.writeInt(22); //4个字节
raf.writeDouble(185.5);//8个字节
raf.writeBoolean(false);//1个字节
//3关闭
raf.close();
}
//读取文件
public static void read() throws Exception{
//1 创建RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile("d:\\random.txt","r");
//2读取
//2.1 skipByte()跳过指定的字节个数
// raf.skipBytes(21);
// raf.skipBytes(21);
//2.2 seek() 设置文件指针的偏移位置
raf.seek(21);
// raf.seek(21);
String name = raf.readUTF();
int age = raf.readInt();
double height = raf.readDouble();
boolean gender = raf.readBoolean();
System.out.println(name+"..."+age+"..."+height+"..."+gender);
//3关闭
raf.close();
}
}
特点:存储属性名和属性值。属性名和属性值都是字符串类型。没有泛型。和流有关。
代码演示:
public class TestProperties {
public static void main(String[] args) throws Exception {
//创建集合
Properties properties=new Properties();
//1添加元素
properties.setProperty("username","张三");
properties.setProperty("age","20");
properties.setProperty("gender","男");
System.out.println(properties);
//2遍历
//2.1 keySet();
//2.2 entrySet();
//2.3 stringPropertyNames();
Set<String> strings = properties.stringPropertyNames();
for (String key : strings) {
System.out.println(key+"..."+properties.getProperty(key));
}
//3和流有关的方法
//3.1 list() 列表输出
System.out.println("-----------list() 列表输出----------");
properties.list(System.out);
//3.2 store() 存储到属性文件(属性文件:后缀名以.properties结尾的文件)
//属性文件的特点:
//1 每行包含一个属性名和属性值,属性名和属性值之间使用等号隔开
//2 属性名和属性值不要使用双引号包裹
//3 属性文件不推荐使用中文, 可以unicode编码表示
//4 属性文件的注释使用#开头
FileOutputStream fos = new FileOutputStream("d:\\stu.properties");
properties.store(fos,"注释内容");
fos.close();
//3.3 load() 加载属性文件 【重点】
Properties properties2=new Properties();
FileInputStream fis=new FileInputStream("d:\\stu.properties");
properties2.load(fis);
fis.close();
System.out.println(properties2);
}
}