java笔记-IO流

本文详细介绍了Java.IO流,包括字节流与字符流的区别和使用,如FileInputStream和FileOutputStream,以及字符流的编码解码、字符转换流如InputStreamReader和OutputStreamWriter。此外,还涵盖了数据流、内存操作流、打印流、随机访问流、序列化与反序列化等,提供全面的IO流知识概览。
摘要由CSDN通过智能技术生成

IO流

处理设备之间的数据传输

在本地电脑上,我们是站在内存角度 看流的流向

​ 看电影 从硬盘中输入

​ 写文件 从内存中输出

流 按照流向分 分为输入流和输出流

​ I InputStream 输入流

​ O outputStream 输出流

按照流读取文件的类型 我们分 字节流和字符流

​ 字节流 读写任意类型文件 Stream

​ 字符流 只能读取文本文件 Reader Writer

A、字节流

字节流继承体系 在java.io包下

字节流分 字节输入流InputStream和字节输出流OutputStream

​ 1. 所有字节输入流父类 InputStream 抽象类

​ a.文件输入流FileInputStream

​ b. ByteArrayInputStream

​ c. ObjectInputStream

​ 2. 所有字节输出流父类 OutputStream 抽象类

​ a.文件输出流FileOutputStream

​ b. ByteArrayOutputStream

​ c. ObjectOutputStream

1.文件输出流FileOutputStream

文件输出流是用于将数据写入 FileFileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter

a.构造方法
1.
FileOutputStream(File file);

File file = new File("a.txt");输出流关联的文件,如果文件不存在,那么运行时系统会自动帮你创建
FileOutputStream out = new FileOutputStream(file);
2.
FileOutputStream(String name);
FileOutputStream out = new FileOutputStream("a.txt");
3.
FileOutputStream(String name,boolean);
FileOutputStream(File file,boolean);
true代表追加写入  每运行一次程序在原来基础上再写一次
false代表不追加
b.写出数据

通过文件输出流,向其所关联的文件中,写出数据

FileOutputStream out = new FileOutputStream("a.txt");
wirte();//参数类型  int b / byte[] b / byte[] b,int off,int len
out.write();//一次写入一个字节
out.write(97);//打开文件后看到a
out.write(300);//超过一个字节的范围,会丢弃多余字节

byte[] bytes = {101,102,103,104};
out.write();//一次写入一个字节数组
out.write(bytes,2,2);//一次写入一个字节数组一部分,从2索引开始,写2个字节  结果  gh

String str = "杨家有女初长成";
byte[] bytes = str.getBytes();//将一个字符串转为字节数组
//UTF-8编码  一个汉字3个字节
out.write(bytes);

out.write("回眸一笑百媚生,六宫粉黛无颜色".getBytes());
out.write("\r\n".getBytes());//写入一个回车换行符
//每个平台系统的换行符都不一样  
//windows平台 换行符 \r\n
//Linux    \n

流用完之后必须释放资源,否则会有内存移除的风险 
1.通知系统释放管理关联文件的资源
2.让IO流变成垃圾,等待垃圾回收器回收
out.close();//关闭流  释放资源



2.文件输入流FileInputStream

FileInputStream 从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。

FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader

a.构造方法
FileInputStream(String name);
FileInputStream(File file);


File file = new File("e.txt");输入流所关联的文件如果不存在就会报错
FileInputStream in = new FileInputStream(file);//输入流所关联的文件如果不存在就会报错

FileInputStream in = new FileInputStream("a.txt");



b.读取文件中数据
read();//参数类型  byte b / byte[] b / byte[] b,int off,int len



FileInputStream in = new FileInputStream("a.txt");
//a.txt  内容  abcdef
int code = in.read();//一次读取一个字节  97
int code = in.read();//最后读不到时   返回-1
in.close();使用完后关闭释放资源

//创建一个空的字节数组充当缓冲区
byte[] bytes = new byte[1024];
int len = in.read(bytes);//将最多bytes长度个code数据存入bytes中  返回实际存入的code个数     
//一次读取1024个字节,放到这个缓冲区中  len就是实际读取的长度 6

int len = in.read(bytes,0,3);//将最多3个数据存入bytes中,并将第一个数据存为bytes[0]

String str = new String(bytes,0,3);
in.close();


字符串转字节数组
byte[] bytes = "abc".getBytes();
字节数组转字符串
String str = new String(bytes);


3.文件复制
a.单字节读写
FileInputStream in = new FileInputStream("a.txt");
FileOutputStream out = new FileOutputStream("E:\\a.txt");

//一个字节一个字节读取 写入   复制文件效率太低
int len = 0;
while((len = in.read())!=-1){
    out.write(len);
    out.flush();//刷新
}
in.close();
out.close();


b.字节数组读写
//一次读取 写入一个字节数组
FileInputStream in = new FileInputStream("a.txt");
FileOutputStream out = new FileOutputStream("E:\\a.txt");

//定义字节数组充当缓冲区   数组长度过长 堆内存溢出不够用 OutOfMemoryError    
byte[] bt = new byte[1024*8];//一般缓冲区大小为 1024*8   8字节
int len = 0;//记录每次读取到的有效字节个数
while((len = in.read(bt))!=-1){
    out.write(bt,0,len);
    out.flush();
}
in.close();
out.close();



c.高效的输入输出流
Ctrl H 可以看一个类的继承关系

new BufferedInputStream();//需要一个InputStream的参数  一个缓冲区大小参数(默认8字节  1024*8)
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file1));

new BufferedOutputStream();
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(file2));


 
int len = 0;
byte bytes = new byte[1024*8];
while((len = bin.read(bytes))!=-1){
    bout.write(bytes,0,len);
    bout.flush();//刷新
}
bin.close();
bout.close();


流的标准异常处理

ctrl alt T 对选定代码进行异常捕获处理

FileInputStream in = null;
FileOutputStream out = null;
try{
    in = new FileInputStream("C:");
    out = new FileOutputStream();
}catch(IOException e){
    e.printStackTrace();
}finally{
    
}



B、字符流

一个中文汉字占两个/三个字节,如果使用字节流操作,需要对汉字进行拆分和合并,为了方便操作中文,java提供了字符流

但是,计算计上存储的最小单位就是字节,要操作数据,本质上还是对最小单位的操作,字符流底层应该还是字节流,因此要使用字符流,就还是要对中文汉字进行拆分和合并,而这就需要编码表作为依据

字符流 = 字节流 + 编码表;

字符流 两个顶层抽象父类 字符输入流Reader 字符输出流Writer

​ 1.字符输入流Reader

​ a.InputStreamReader

​ b.BufferedReader

​ 2.字符输出流Writer

​ a.OutputStreamWriter

​ b.BufferedWriter

1.编码和解码

​ 编码:把字符串转换成字节数组

String str = "今晚老地方见面"byte[] bytes = str.getBytes();     // 采用平台默认的码表进行编码

​ 解码:把字节数组转换成字符串

String s = new String(bytes);//采用平台默认的码表进行解码

编码解码需要通过码表 无参构造就采用平台默认的码表 解码码表和编码码表不一致 就会产生乱码

String str = "今晚老地方见面";
byte[] bytes = str.getBytes(码表); //可以传入参数  使用指定码表
String s = new String(bytes,码表);//如果解码码表和编码码表不一致  就会产生乱码


2.字符转换流

InputStreamReader OutputStreamWriter

A、OutputStreamWriter

字符流通向字节流的桥梁 使用指定的码表

构造方法
//输出流所关联的文件如果不存在就会自动创建  
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("a.txt"),码表);//也可以指定码表  
out.writer('你');//写字符就行,不需要写转换字节   一次写一个字符
out.writer("今天是大暑"); //一次写一个字符串
out.writer("今天是大暑",0,5);//从0开始写5个
out.writer(new char[]{'n','好','5'});   //一次写入一个字符数组
out.writer(new char[]{'n','好','5'},0,2);    //一次写入一个字符数组一部分


想追加就在传入的FileOutputStream传入true参数
B、InputStreamReader

字节流通过字符流的桥梁,使用指定码表 读取字节并将其转为字符

InputStreamReader(InputStream in);

//输入流关联的文件如果不存在就会报错
InputStreamReader in = new InputStreamReader(new FileInputStream(file)); 
int ch = in.read();//一次读取一个字符  返回该字符在编码表中的码数
System.out.println(ch);//如需看字符需要将ch通过查询编码表强转为char
int ch = in.read();  //读不到返回-1

char[] chars = new char[1024];//字符数组充当缓冲区

1.int len = in.read(chars);//返回值是实际读取到的字符个数
2.len = in.read(chars,0,3);//一次读取字符数组一部分装入缓冲区   字符数组从0开始装3个

String str = new String(chars);
String str = new String(chars,0,len);
String str = String.valueOf(chars,0,len);

C、采用字符流复制文本文件
InputStreamReader in = new InputStreamReader(new FileInputStringReader(file1)); 
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file2));


一次一个字符
int len = 0;
while((len = in.read())!=-1){时
    out.writer(len);
    out.flush();//字符流写入如果不刷新  不会写入  
}
in.close();
out.close();  //此处也带有刷新功能  刷新并关闭

一次一个字符数组
char[] chars = new char[1000];//
int len = 0;//读取到的有效字符个数
while((len = in.read(chars))!=-1){
    out.writer(chars,0,len);
    out.flush();//字符流如果不刷新  不会写入  
}
in.close();
out.close();  //此处也带有刷新功能  刷新并关闭

InputStreamReader 的便捷子类 FileReader (不能指定编码,只能使用平台默认编码)

OutputStreamWriter 的便捷子类 FileWriter (不能指定编码,只能使用平台默认编码)

FileReader(File file);
FileReader(String filename);

FileWirter(File file);
FileWirter(String filename);
FileWirter(File file,boolean append);//如果第二个参数为true 则将数据写到文件末尾处,而不是开头
FileWirter(String filename,boolean append);

两个子类方法与父类几乎一致,没有特有方法,都是从父类继承过来的 只是不能指定编码

4.高效字符流

BufferedReader 从字符输入流中读取中文,缓冲各个字符,从而实现字符、数组和行的高效读取,也可以指定缓冲区的大小

BufferedReader();//参数类型Reader r

BufferedWriter

BufferedWriter();//参数类型 Writer w

BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
char[] chars = new char[1024];
int len = 0;
while((len = br.read(chars))!=-1){
    bw.writer(chars,0,len);
    bw.flush;
}
br.close();
bw.close();

br.readLine();//一次读取一行  包括空格行
bw.newLine();//写一个换行符  具有平台兼容性   //换行符占两个字节

//读一行写一行  复制文件
String line = null;
while((line = br.readLine())!=null){
    bw.write(line);
    bw.newLine();
    bw.flush();
}
br.close();
bw.close();






C.其他流

1.数据输入输出流 (字节流)

​ DataInputStream

​ DataOutputStream

特点:能够读写基本数据类型

DateInputStream(InputStream in);
DataOutputStream(OutputStream out);
DateOutputStream dos = new DateOutputStream(new FileOutputStream("a.txt"));
dos.writeBoolean(true);
dos.writeDouble(3.14);
dos.writeInt(100);
dos.writeUTF("你好世界");
dos.close();

//什么顺序写就什么顺序读
DateInputStream dis = new DateInputStream(new FileInputStream("a.txt"));
boolean b = dis.readBoolean();
double d = dis


2.内存操作流

特点:不关联任何文件,只在内存中对数据进行读写 关闭此流是无效的,此类方法在关闭此流后仍可使用,而不会产生IO流异常

操作字节数组

ByteArrayInputStream

ByteArrayOutputStream

ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write("横眉冷对千夫指".getBytes());
out.write("俯首甘为孺子牛".getBytes());

//取出缓冲区中的数据
byte[] b = out.toByteArray();
String s = new String(b);

//也可以直接通过此方法取  但只限于String类型
//String s = out.toString();

ByteArrayInputStream in = new ByteArrayInputStream(b);//自带一个缓冲区(数组)需要从
byte[] bytes = new byte[1024*8];
int len = in.read(bytes);
String s = new String(bytes,0,len);

操作字符数组

CharArrayWriter

CharArrayReader

CharArrayWriter cw = new CharArrayWriter();
cw.write("abc");
cw.write("cba");
cw.write("bac");
char[] chars = cw.toCharArray();
String s = new String(chars);

操作字符串

底层用StringBuffer为缓冲区

StringWriter

StringReader

StringWriter sw = new StringWriter();
sw.append("as");
sw.write("sd");


3.打印流
a.构造方法
PrintWriter(File file);
PrintWriter(OutputStream out);
PrintWriter(OutputStream out,boolean b);
PrintWriter(String fileName);
PrintWriter(String fileName,boolean b);

PrintStream(File file);
PrintStream(OutputStream out);
PrintStream(OutputStream out,boolean b);
PrintStream(String fileName);
PrintStream(String fileName,boolean b);
b.特点:

​ 1.只操作目的地,不能操作数据源(不能读取数据) 只有输出流

​ 2.可以操作任意数据类型的数据 使用print()方法可以写任意数据类型

​ 3.如果我们启用自动刷新(构造方法第二个参数传入true ),那么在调用println、printf或format方法中的一个方法的时候,会自动完成刷新

public PrintWriter(OutputStream out,boolean b);
PrintWriter pw = new PrintWriter("abc.txt",true);//开启自动刷新
pw.println("abcde");
pw.println(100);

​ 4.这个流可以直接对文件进行操作(可以直接操作文件的流:就是构造方法的参数可以传递文件或者文件路径)

c.字节打印流

PrintStream

PrintStream(File file);
PrintStream(OutputStream out);
PrintStream(OutputStream out,boolean b);
PrintStream(String fileName);
PrintStream(String fileName,boolean b);

//
PrintStream out = System.out;
PrintStream ps = new PrintStream(System.out);
ps.print(value);//将指定内容输出到显示器

ps.print(value);
ps.println();//换行
ps.println(value);//相当于ps.print(value)后再ps.println()
ps.write();
ps.append();


d.字符打印流

需要关联文件

PrintWriter pw = new PrintWriter(new FileOutputStream(“c.txt”),true);//可以加上true,再使用println()或printf()或format方法使其自动刷新

pw.write();

pw.flush();//write方法 需要刷新才生效

pw.println()//带有换行符

4.键盘录入的第二种方式
1.Scanner 
2.BufferedReader 的 readLine()方法
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
5.随机访问流 RandomAccessFile

常用于 断点下载(第一次未下载完,第二次接着下) 和断点复制

特点 能读能写 支持读写基本数据类型

RandomAccessFile 类不属于流 是Object类的子类,融合了InputStream和OutputStream的功能

有一个文件指针 能够记录文件读写的位置

我们可以通过getFilePointer()方法获取文件指针,并且可以通过seek方法设置文件指针位置

构造方法

RandomAccessFile(File file,String mode);
RandomAccessFile(String name,String mode);

RandomAccessFile ra = new RandomAccessFile(new File("e.txt"),"rw");//参数2代表模式   "rw"可读可写
ra.writeBoolean();


6.序列化与反序列化

序列化 把对象保存到硬盘上

反序列化 把对象读取到内存中

a.序列化流

ObjectOutputStream

​ 将java对象的基本数据类型和图形写入OutputStream,可以使用ObjectOutputStream读取(重构)对象。通过在流中使用文件可以实现对象的持久存储

把对象序列化到硬盘上 就要求该类实现Serializable接口 然后该类对象才能正常

注:Serializable 接口中没有任何方法 标记接口(给该类打标记 ,让jvm支持序列化 告诉虚拟机,我要序列化这个对象)

在实现了Serializable接口后,最好再写一个static final long serialVersionUID = 9746L,这样将对象存到硬盘上后,对象某个成员变量修饰符被修改,我们再次读取时会jvm会认为是同一个文件,就能读取成功

transient 对象的某个成员变量加上该关键字后 序列化该对象时不会将该对象的该成员变量一起序列化

如果要存储多个对象,我们可以将多个对象放到集合中,将集合序列化到硬盘,这样我们取某个对象时就很方便了

writeObject();//将指定对象写入ObjectOutputStream
b.反序列化流

ObjectInputStream

readObject();//从ObjectintputStream读取对象
7.Properties 属性集合

Properties 属性集合 经常用它来读写配置文件

​ 属于双列集合 继承于Hashtable ,但不建议使用put和putAll方法,推荐使用setProperty()方法

​ 规定 键值是String类型 不能设泛型

Properties类表示了一个持久的属性集,可以保存在流中或从流中加载。属性列表中的每一个键及其对应的值都是一个字符串。

一个属性列表可包含另一个属性列表作为它的“默认值”,如果未能在原有的属性列表中搜索到属性键,则搜索第二个属性类表

Properties p = new Properties();
//特有方法存储键值
p.setProperty("a","1");
String str = p.getProperty("a");   键找值  如果键没有找到对应的值 则返回null  
String st = p.getProperty("a","未找到");  设置第二个参数  键没有找到对应的值 返回设置的默认值

//读取配置文件(将配置信息存到该集合中)  要求配置文件键值用等号 = 连接   Username="张三" 
load()  按简单的面向行的格式从字符输入流中读取属性列表(键值对)
Password="123456"
p.load(new FileReader("a.txt"));

store();  以 适合调用load()方法 的格式,将Properties集合中的键值对写入输出流
//将集合中信息写到文件中
p.setProperty("Username","王五");
p.setProperty("Password","1234565");
p.store(new FileWriter("用户信息.txt"),null);


8.顺序流

只有顺序输入流

顺序输入流 SequenceInputStream

表示其他输入流的逻辑串联 他从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

同时,在使用close()方法时,会将被合并的所有输入流一起关闭

//构造方法1 将两个输入流合并为一个输入流 先读取in1,在读取in2
SequenceInputStream si = new SequenceInputStream(InputStream in1,InputStream in2);
//构造方法2 该构造方法需要一个 存储元素为输入流的集合的迭代器 作为参数
SequenceInputStream si = new SequenceInputStream(Enumeration<? extends InputStream> e);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值