目录
1.IO流的分类
1.1 通过流分类:输入流,输出流
1.2 通过数据单位不同分分类:字符流,字节流
1.3 抽象类
1.4 各抽象类的选用
2.文件流的使用
2.1 字节输出流:FileOutputStream
2.2 字节输入流:FileInputStream
2.3 缓冲区类(高效类):BufferedOutputStream,BufferedInputStream
3.转换流的使用
3.1 字节流转化为字符流:OutputStreamWriter,InputStreamReader
3.2 OutputStreamWriter,InputStreamReader的封装类(简化写法):FileWriter,FileReader
3.3 缓冲区类(高效类):BufferedWriter,BufferedReader
4.数据输入输出流
5.内存操作流
6.打印流
7.标准输入输出流
8.随机访问流
9.合并流
10.序列化流反序列化流
11.Properties
输入流:从接收器输入到java程序。
输出流:输出流接受输出字节并将这些字节发送到某个接收器,也就是从java程序输出到接收器。
在java版本中是先有字节流,再有字符流,1字符 = 2字节
字节流:每次传输一个字节,一个中文汉字是两个字节,会出现乱码。
字符流:每次传输两个字节,一般传输中文
字节输出流:OutputStream
字节输入流:InputStream
字符输出流:Writer
字符输入流:Reader
选用输入,输出流通过需求选用
选用字符,还是字节,一般用记事本打开是看得懂的用字符,看不懂的用字符。字节流更加适用于音频文件、图片、歌曲。
向文件中写入数据
public static void main(String[] args) throws IOException {
//追加写入,append为true追加
FileOutputStream fos = new FileOutputStream("E:\\b.txt",true);
byte[] b = {'a','b','c','d'};
fos.write(97);//底层是二进制数据,记事本会找到对应的字符值
fos.write("\n".getBytes());//加入换行,一般windows写法是\r\n,linux是\n,mac是\r
fos.write("hello,world".getBytes());
fos.write("\n".getBytes());
fos.write(b,1,2);
fos.write("\n".getBytes());
fos.close();
}
程序分为三部分:
(1)创建字节输出流对象:这一步创建了文件,创建了fos对象,并把fos对象指向了此文件
(2)写入数据
(3)释放资源:释放了文件所占用的相关资源,变成垃圾,通知系统回收
异常处理方式:
异常有很多变形,这里用try...catch...catch...finally...(这里fos可能为空,如当找不到指定的盘符是,或者说是我只有一个C盘,得到fos为空)
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("E:\\b.txt",true);
fos.write("异常处理".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fos != null){//fos不为空才执行,因为finally是默认执行的
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
读取文件:一次读取一个字节:int read()
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("E:\\b.txt");
int by = 0;
//读取,赋值,判断
while((by=fis.read())!=-1){
System.out.print((char) by);
}
fis.close();
}
读取文件如果没有相应文件不会为你创建文件,这里用的 int read().一次传输一个字节,返回的是数据字节,当返回值为-1,则表示传输结束,汉字是两个字节,会被拆分,返回值的第一个字节都是负数,第二个字节可能是正数,也是合并的判断依据
英文传输返回值:
[97, 98, 99, 100, 101, 102]
对应:abcdef
中文传输返回值:
[-26, -79, -119, -27, -83, -105, -26, -117, -122, -27, -120, -122, -28, -68, -96, -24, -66, -109]
对应:汉字拆分传输(UTF-8编码表示字符最多占三个字节)
一次读取多个字节:public int read(byte[ ] b)
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("e:\\b.txt");
byte[] by = new byte[1024];
int len = 0;
while((len = fis.read(by))!=-1){
//避免读出的数据不满足数组大小
System.out.print(new String(by,0,len));
}
fis.close();
}
public int read(byte[ ] b):把读取的数据存到数组b里,返回值是实际读取到的字节个数,如果缓冲区没有了就返回-1
注意: 这里by数组的长度一般是1024或者1024的整数倍
相对于一个字节的读取快了1024倍或者1024的整数倍,传输视频等大文件时使用
传输图片练习代码
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\图片.jpeg");
FileOutputStream fos = new FileOutputStream("E:\\copy.jpeg");
byte[] by = new byte[1024];
int len = 0;
while((len = fis.read(by)) != -1){
fos.write(by,0,len);
}
fos.close();
fis.close();
}
缓冲区类类似于一个杯子,用来装水(水是指OutputStream,InputStream),运行效率高,代码体现:
//向文件写入数据
public static void main(String[] args) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream("e:\\b.txt"));
bos.write("hello".getBytes());
bos.close();
}
//从文件读取数据
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new
FileInputStream("e:\\b.txt"));
byte[] by = new byte[1024];
int len = 0;
while ((len = bis.read(by)) != -1){
System.out.println(new String(by,0,len));
}
bis.close();
}
由于用的是字符,有很多字符集,写入和读取的字符集要一致,不一致会乱码。
//写入数据
public static void main(String[] args) throws IOException {
//使用指定字符集,把字节流转换为字符流
OutputStreamWriter osw = new OutputStreamWriter(new
FileOutputStream("e:\\b.txt"),"UTF-8");
osw.write("汉字");
//刷新一下,但流未关闭,还能写入数据
osw.flush();
//先刷新,在关闭此流
osw.close();
}
//从文件读出数据
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new
FileInputStream("e:\\b.txt"),"UTF-8");
int len = 0;
char[] by = new char[1024];
while((len = isr.read(by)) != -1){
System.out.print(new String(by,0,len));
}
isr.close();
}
flush和close的区别:在写入字符时,字符是在缓冲区的,文件里并没有,此时flush一下后,就会进入文件。flush能写入数据,但并没有把流关闭,随后还能写入数据。而close是刷新写入数据后把流关闭,随后就不能写入数据了。
利用封装的类复制文件,代码:
public static void main(String[] args) throws IOException{
FileWriter osw = new FileWriter("e:\\b.txt");
FileReader isr = new FileReader("e:\\a.txt");
int len = 0;
char[] chars = new char[1024];
while ((len = isr.read(chars)) != -1){
osw.write(chars,0,len);
//osw.flush();
}
osw.close();
isr.close();
}
//写入
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\b.txt"));
bw.write("hello");
bw.close();
}
//读出
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("e:\\b.txt"));
int len = 0;
char[] c = new char[1024];
while((len = br.read(c)) != -1){
System.out.println(c);
}
br.close();
}
这两个类有特殊的方法:
public void newLine():系统决定换行符
public String readLine():一次读取一行数据,没有数据时返回null
方法的使用:
//复制文件练习
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("e:\\a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\b.txt"));
String str = null;
while((str = br.readLine()) != null){
bw.write(str);
bw.newLine();
}
bw.close();
br.close();
}
BufferReader的子类:LineNumberReader
其特有功能:
特殊方法: int getLineNumber() :获取当前行号
void setLineNumber(int lineNumber):设置当前行号
代码:
public static void main(String[] args) throws IOException {
LineNumberReader lnr = new LineNumberReader(new FileReader("e:\\b.txt"));
lnr.setLineNumber(11);//从第12行开始
String str = null;
while((str = lnr.readLine()) != null){
int line = lnr.getLineNumber();
System.out.println(line +":"+str);
}
}
运行结果:
12:hello
13:world
14:java
DataOutputStream:FilterOutputStream的子类
数据输入输出流可以读写任意类型数据:
public static void main(String[] args) throws IOException {
write();
read();
}
private static void read() throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("e:\\b.txt"));
int i = dis.readInt();
char c = dis.readChar();
float f = dis.readFloat();
double d = dis.readDouble();
dis.close();
System.out.println(i);
System.out.println(c);
System.out.println(f);
System.out.println(d);
}
private static void write() throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("e:\\b.txt"));
dos.writeInt(12);
dos.writeChar('a');
dos.writeFloat(12.32f);
dos.writeDouble(14.36);
dos.close();
}
不需要文件,用于处理临时存储信息,程序结束,数据就从内存中消失,这个有读有写,对应的读的操作类:
字节数组:java.io.InputStream 继承者 java.io.ByteArrayInputStream
字符数组:java.io.Reader 继承者 java.io.CharArrayReader
字符串:java.io.Reader 继承者 java.io.StringReader
字节数组(三种类似)的写入读出操作:
public static void main(String[] args) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("hello".getBytes());
baos.write("java".getBytes());
//这个close()不起任何作用,内部源码是个空的,主要是为迎合父类操作
//baos.close();
byte[] by = baos.toByteArray();
ByteArrayInputStream bios = new ByteArrayInputStream(by);
int len = 0;
while((len = bios.read()) != -1){
System.out.print((char) len);
}
//这个close()也是
bios.close();
}
打印流读字面意思就可以知道这个只有向文件写数据,没有读数据:
字节打印流:java.io.FilterOutputStream 继承者 java.io.PrintStream
字符打印流:java.io.Writer 继承者 java.io.PrintWriter
特点:
1.只有写数据,没有读数据,只能操作目的地,不能操作数据源
2.可以操作任意类型数据:print(),println()
3.如果启用了自动刷新,能够自动刷新
PrintWriter pw = new PrintWriter(new FileWriter("e:\\b.txt"),true);
启用自动刷新,但必须使用println()(包含了写入,换行,刷新)
4.该流可以直接操作文件
那些可直接操作文件的流:FileOutputStream,FileInputStream,FileWriter,FileReader,PrintStream,PrintWriter
代码示例:
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileWriter("e:\\b.txt"),true);
// pw.print("hello");
// pw.print(100);
// pw.print("java");
pw.println("hello");
pw.println(100);
pw.println("java");
// pw.close();// 代码中close()也会刷新,测试自动刷新,可以把close()注释
}
public static final InputStream in
public static final PrintStream out标准输出流:System.out 显示器
标准输入流:System.in 键盘
与我们常用的输入输出一样,在输出流中用打印流的方法都能使用 :public static final PrintStream out
public static void main(String[] args) {
PrintStream p = System.out;
p.println(11);//与下面意思一样
System.out.println(12);
}
此类不是一个流,是Object的子类
融合了InputStream和OutputStream
支持对文件随机访问读取和写入
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("E:\\b.txt","rw");//第二个参数是操作文件的模式,读写两种写法一样
// raf.writeInt(100);
// raf.writeChar('a');
// int i = raf.readInt();
// System.out.println(i);
// System.out.println("当前文件指针位置"+raf.getFilePointer());
raf.seek(4);//设置指针位置
char c = raf.readChar();
System.out.println(c);
System.out.println("当前文件指针位置"+raf.getFilePointer());
raf.close();
}
字面意思,一次同时读取多个文件。只有读操作
构造方法:SequenceInputStream(InputStream,InputStream):合并两个文件
SequenceInputStream(Enumeration extends InputStream> e):合并多个文件
把a.txt和b.txt的文件内容传到c.txt,两种方式:
public static void main(String[] args) throws IOException {
//合并两个文件
// InputStream is1 = new FileInputStream("e:\\a.txt");
// InputStream is2 = new FileInputStream("e:\\b.txt");
// SequenceInputStream sis = new SequenceInputStream(is1,is2);
//合并多个文件
Vector vi = new Vector();
InputStream is1 = new FileInputStream("e:\\a.txt");
InputStream is2 = new FileInputStream("e:\\b.txt");
vi.add(is1);
vi.add(is2);
//利用构造方法:SequenceInputStream(Enumeration extends InputStream> e)
Enumeration ei = vi.elements();//返回此向量的组件的枚举。
SequenceInputStream sis = new SequenceInputStream(ei);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\c.txt"));
int len = 0;
byte[] by = new byte[1024];
while ((len = sis.read(by)) != -1){
bos.write(by,0,len);
}
bos.close();
sis.close();
}
序列化流(对像操作流):写 ObjectOutputStream,对象--》流
把对象按照流一样的方式存入文本文件或者在网络中传输
反序列化流:读 ObjectInputStream,流--》对象
把文本文件中的流对象或者网络中的流对象数据还原为对象
public static void main(String[] args) throws IOException, ClassNotFoundException {
write();
read();
}
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:\\c.txt"));
Object o = ois.readObject();
System.out.println(o);
ois.close();
}
private static void write() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e:\\c.txt"));
Student s = new Student("张三",100,120,148);
oos.writeObject(s);
oos.close();
}
/**
* Serializable:序列化
* 如果某个变量不想被序列化,可加入关键字transient
*/
public class Student implements Serializable {
//姓名
public String name;
//语文成绩
public int chinese;
//数学成绩
public int math;
//英语成绩
public int english;
......
}
属性集合类,是一个可以和IO流相结合使用的集合类。可以保存在流中或者从流中加载。属性列表中每一个键所对应的值都是字符串。
java.util.Hashtable
特有功能
bject setProperty(String key, String value):调用 Hashtable 的方法 put。
String getProperty(String key) :用指定的键在此属性列表中搜索属性。
Set
stringPropertyNames() : 返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
文件与此类的结合:
方法: void load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
void store(Writer writer, String comments) 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
使用代码:
public static void main(String[] args) throws IOException {
myLoad();
myStore();
}
private static void myStore() throws IOException{
Properties p = new Properties();
Writer w = new FileWriter("e:\\c.txt");
p.setProperty("张飞","丈八蛇矛");
p.setProperty("吕布","方天画戟");
p.setProperty("刘备","双股剑");
p.store(w,"hero");
w.close();
}
private static void myLoad() throws IOException{
Properties p = new Properties();
Reader r = new FileReader("e:\\c.txt");
p.load(r);
System.out.println(p);
r.close();
}