java基础IO流

IO

1.1 

1.1.1 的概念

(stream)是指一连串流动字节/字符,按照进先出的方式发送的信息的通道中。

 

数据:流入通道中的数据的来源

目的地:流出通道的数据的目的地

 

1.1.2 输入流和输出流

数据源的数据流入程序的流称为输入流

 

 

程序中的数据流出到目的地的称为输出流

 

 

1.1.3 的分类

 

 

 

 

1.2 InputStream/OutputStream

inputstream 表示字节输入流,是所有字节输入流的抽象父类。提供了read/read(byte[] buf) 用于读取一个或者多个字节close用于关闭输入流

 

outputstream 表示字节输流,是所有字节输流的抽象父类。

1.2.1 FileInputStream

FileInputStream 专门用于读取文件的字节输入流。可以用于读取文本性文件(存在编码)图片音频视频等二进制文件。

 

一次读取一个字节

package cn.sxt01.fileinputstream;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

 

public class Test01 {

public static void main(String[] args) {

// 需求:读取c.txt中的内容

 

File file = new File("d:\\javatest\\c.txt");

 

// 1】构建输入流(管道)

FileInputStream fis = null;

 

try {

fis = new FileInputStream(file);

System.out.println(fis);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

 

// 2】读取一个字节

int r = 0;

try {

r = fis.read();

} catch (IOException e) {

e.printStackTrace();

}

 

System.out.println((char)r);

 

// 3】关闭流

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

read() 一次读取一个字节,如果已到达文件末尾,则返回 -1

 

一次读取多个字节

package cn.sxt01.fileinputstream;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.util.Arrays;

 

public class Test03 {

public static void main(String[] args) {

// 需求:读取c.txt中的内容

 

File file = new File("d:\\javatest\\c.txt");

 

// 1】构建输入流(管道)

FileInputStream fis = null;

 

try {

fis = new FileInputStream(file);

System.out.println(fis);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

 

// 2】读取一个字节

int len = 0; // 读取到缓冲区中的字节个数

byte[] buf = new byte[2]; // 字节缓冲区

StringBuilder sb = new StringBuilder();

try {

 

while( (len=fis.read(buf)) != -1 ) {

String tmp = new String(buf,0,len);

sb.append(tmp);

}

 

} catch (IOException e) {

e.printStackTrace();

}

 

System.out.println(sb);

 

// 3】关闭流

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

read(byte[] buf)一次读取多个字节到字节缓冲区,并返回读取的字节个数。

 

 

1.2.2 FileOutputStream

 

一次写一个字节

package cn.sxt01.fileouputstream;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

 

public class Test01 {

public static void main(String[] args) {

// 需求:写入helloworld d.txt中的内容

 

File file = new File("d:\\javatest\\d.txt");

 

// 1】创建输出流(管道)

FileOutputStream fos = null;

 

try {

fos = new FileOutputStream(file);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

 

//2】写入信息到输出流

try {

fos.write('h');

fos.write('e');

fos.write('l');

fos.write('l');

fos.write('o');

} catch (IOException e) {

e.printStackTrace();

}

 

// 3】刷新缓冲区

try {

fos.flush();

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

调用write(int)方法,把一个字节写入到输出流,输出流会立即把该字节写入文件中。

所以,如果不手动代用flush方法信息也写入到文件中。

 

一次写多个字节(指定编码)

package cn.sxt01.fileouputstream;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

 

public class Test02 {

public static void main(String[] args) {

// 需求:写入helloworld d.txt中的内容

 

File file = new File("d:\\javatest\\d.txt");

 

// 1】创建输出流(管道)

FileOutputStream fos = null;

 

try {

fos = new FileOutputStream(file);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

 

//2】写入信息到输出流

try {

String str = "hello world中国";

 

// 默认gbk编码

/*byte[] buf = str.getBytes();

fos.write(buf);*/

 

byte[] buf = str.getBytes("utf8");

fos.write(buf);

 

} catch (IOException e) {

e.printStackTrace();

}

 

// 3】刷新缓冲区

try {

fos.flush();

// 4】关闭文件

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

write(byte[] buf)一次写入多个字节到输出流。注意,此时的字节流已经经过编码。默认系统编码(win7:gbk)

write(byte[] buf,offset,len) 一次写入buf中从offset开始,len个长度的字节到输出流。

 

综合案例:

[1]把目录中的logo.jpg复制到工程

[2]请打印复制进度

 

1.3 Reader/Writer

Reader 字符输入流的抽象父类。提供了read()一次读取一个字符;read(char[] buf)一次多去多个字符到字符缓冲区。

 

Writer 字符输出流的抽象父类提供

write()写入单个字符

write(char[] cbuf) 写入多个字符

write(String str) 写入字符串

1.3.1 FileReader

FileReader是文件字符输入流,专门用于读取文本性文件不能读取图片、音频、视频等二进制文件。

 

一次读取一个字符

package cn.sxt03.filereader;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

 

public class Test01 {

public static void main(String[] args) {

 

File file = new File("d:\\javatest\\d.txt");

 

// 1】建立字符输入流

FileReader fr = null;

try {

fr = new FileReader(file);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

 

// 2】一次读取一个字符

int r = 0;

try {

/*r = fr.read();

r = fr.read();

r = fr.read();

r = fr.read();

r = fr.read();

r = fr.read();

 

System.out.println(r);*/

 

/*

中国abc\r\n

中国你好你好

*/

StringBuilder sb = new StringBuilder();

while( (r=fr.read()) != -1 ) {

sb.append((char)r);

}

System.out.println(sb);

 

 

} catch (IOException e) {

e.printStackTrace();

}

 

// 3】关闭输入流

try {

fr.close();

} catch (IOException e) {

e.printStackTrace();

}

 

 

 

}

}

 

 

一次读取多个字符

package cn.sxt03.filereader;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.util.Arrays;

 

public class Test01 {

public static void main(String[] args) {

 

File file = new File("d:\\javatest\\d.txt");

 

// 1】建立字符输入流

FileReader fr = null;

try {

fr = new FileReader(file);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

 

// 2】一次读取多个字符

int len = 0;

char[] cbuf = new char[2];

try {

 

/*

len = fr.read(cbuf);

len = fr.read(cbuf);

len = fr.read(cbuf);

 

System.out.println(len);

System.out.println(Arrays.toString(cbuf));

*/

 

StringBuilder sb = new StringBuilder();

while( (len=fr.read(cbuf)) != -1) {

sb.append(cbuf, 0, len);

}

System.out.println(sb);

 

 

} catch (IOException e) {

e.printStackTrace();

}

 

// 3】关闭输入流

try {

fr.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

 

1.3.2 FileWriter

FileWriter 文件字符输出流,专门用于写入文本性文件。

通过FileWriter构造方法构造的对象写入文件时编码是系统默认编码(win7:gbk)

由于写入的是字符,字符在写入时一定要经过编码,所以FileWriter内部有一个字符缓冲区用于存放写入字符在调用flush时,FileWriter字符缓冲区的字符编码成字节然后写入目标文件。

 

package cn.sxt03.filewriter;

 

import java.io.File;

import java.io.FileWriter;

import java.io.IOException;

 

public class Test01 {

public static void main(String[] args) {

 

File file = new File("d:\\javatest\\e.txt");

 

FileWriter fw = null;

 

// 1】建立输出流管道

try {

/*

 * append:表示写入文件的方式

 * true:追加 false:覆盖

 */

fw = new FileWriter(file,false);

} catch (IOException e) {

e.printStackTrace();

}

 

// 2】写入

try {

 

// 写入一个字符

/*fw.write('');

fw.write('');*/

 

// 写入一个字符数组

/*char[] cbuf = {'','','\r','\n','a','b','c'};

fw.write(cbuf);*/

 

// 写入一个字符串

fw.write("中国abc");

 

} catch (IOException e) {

e.printStackTrace();

}

 

// 3】刷新

try {

fw.flush();

fw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

 

思考:如何读取一个utf8编码的文本文件。

 

1.4 转换

所谓转换可以把字节流转化成字符流的转换流

 

InputStreamReader 是字节流通向字符流的桥梁,它使用指定的字符集读取字节并将其解码为字符。

OutputStreamWriter 是字符流通向字节流的桥梁,可使用指定的字符集将要写入流中的字符编码成字节

 

1.4.1 转换流工作原理

 

 

utf8编码写入文件

package cn.sxt04.outputstramwriter;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.FileWriter;

import java.io.IOException;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

 

public class Test01 {

public static void main(String[] args) throws FileNotFoundException,IOException {

 

// 需求:写入 “中国abc” 以utf8编码写入

File file = new File("d:\\javatest\\g.txt");

 

FileOutputStream out = new FileOutputStream(file);

OutputStreamWriter osw = new OutputStreamWriter(out, "utf8");

 

osw.write('');

char[] cbuf = {'','a'};

osw.write(cbuf);

 

osw.write("中国abc");

 

osw.flush();

osw.close();

}

}

 

utf8编码读取文件

public class Test02 {

public static void main(String[] args) throws FileNotFoundException,IOException {

 

// 需求:读取g.txt的内容

File file = new File("d:\\javatest\\g.txt");

 

FileInputStream fis = new FileInputStream(file);

InputStreamReader isr = new InputStreamReader(fis, "utf8");

 

/*int r = isr.read();

System.out.println((char)r);*/

 

char[] cbuf = new char[2];

int len = 0;

StringBuilder sb = new StringBuilder();

while( (len=isr.read(cbuf)) != -1) {

sb.append(cbuf,0,len);

}

System.out.println(sb);

 

}

}

 

思考:FileReaderInputStreamReader的关系?

 

注意:win7手动创建utf8编码的文件(utf8-bom)

java程序写入的utf8文件不带bom

public class Test03 {

public static void main(String[] args) throws FileNotFoundException,IOException {

 

// 需求:读取win手动创建的utf8编码的h.txt的内容

File file = new File("d:\\javatest\\h.txt");

 

FileInputStream fis = new FileInputStream(file);

InputStreamReader isr = new InputStreamReader(fis, "utf8");

 

/*int r = isr.read();

System.out.println((char)r);*/

 

char[] cbuf = new char[2];

int len = 0;

StringBuilder sb = new StringBuilder();

while( (len=isr.read(cbuf)) != -1) {

sb.append(cbuf,0,len);

}

System.out.println(sb);

 

}

}

 

1.5 BufferedReader/BufferedWriter

FileReader 提供的读取字符的方式效率稍低,如果高效字符方式,可以使用BufferedReader/BufferedWriter

 

1.5.1 BufferedReader

BufferedReader继承Reader,专门用于高效的处理文本提供了readLine方法用于一次读取一行文本。

 

一首诗读取到控制台显示

package cn.sxt01.bufferedreader;

 

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

 

public class Test01 {

public static void main(String[] args) throws FileNotFoundException,IOException {

 

File file = new File("d:\\javatest\\i.txt");

 

// ctrl+t:查看类继承关系

FileReader reader = new FileReader(file);

BufferedReader br = new BufferedReader(reader);

 

// 一次读取一行

/*

String str = br.readLine();

str = br.readLine();

str = br.readLine();

str = br.readLine();

str = br.readLine();

System.out.println(str);

*/

 

 

String line;

while( (line=br.readLine() ) != null) {

System.out.println(line);

}

 

 

br.close();

reader.close();

}

}

 

 

1.5.2 BufferedWriter

BufferedWriter Writer的子类,专门用于高效的写入文本。提供了writer(String)newLine()方法,写入完成后调用flush()刷新缓冲区。

package cn.sxt01.bufferedwriter;

 

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStreamWriter;

 

public class Test01 {

public static void main(String[] args) throws FileNotFoundException,IOException {

 

// 需求:以utf8存入一首诗

File file = new File("d:\\javatest\\k.txt");

 

FileOutputStream out =  new FileOutputStream(file);

OutputStreamWriter osw = new OutputStreamWriter(out, "utf8");

 

BufferedWriter bw = new BufferedWriter(osw);

 

bw.write("床前明月光,");

bw.newLine();

 

bw.write("疑似地上霜。");

bw.newLine();

 

bw.flush();

 

bw.close();

osw.close();

out.close();

 

}

}

 

1.6 标准输入输出流

 

 

1.6.1 标准输入流

javaSystem.in表示标准输入流,属于InputStream字节输入流,标准输入设备():鼠标、键盘、手写板麦克风触摸屏等

 

 

需求:键盘输入一个字符并打印出来。

package cn.sxt02.inout;

 

import java.io.IOException;

import java.io.InputStream;

 

public class Test01 {

public static void main(String[] args) throws IOException {

 

// 从控制台输入一个字符并打印

InputStream in = System.in;

 

// 1】一次读取一个字节:(输入/数据源是键盘)

// int r =  in.read();

// System.out.println((char)r);

 

// 2】一次读取多个字节

byte[]  buf = new byte[1024];

int len = 0;

len = in.read(buf);

 

// 默认控制台是gbk编码

String str = new String(buf, 0, len);

System.out.println(str);

}

}

 

1.6.2 标准输出

javaSystem.out表示标准输出属于PrintStream。标准的输出设备():显示器、显示屏

 

需求:文件中读取文件内容并显示在标准输出设备上。

package cn.sxt02.inout;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.PrintStream;

 

public class Test02 {

public static void main(String[] args) throws IOException {

 

// 思考:为什么会乱码?

File file = new java.io.File("d:\\javatest\\i.txt");

 

FileInputStream fis = new FileInputStream(file);

 

// 标准输出流(gbk

PrintStream ps = System.out;

 

int len = 0;

byte[] buf = new byte[2];

while( (len=fis.read(buf)) != -1 ) {

ps.write(buf, 0, len);

}

 

fis.close();

 

}

}

 

通过打印流直接写入文件

package cn.sxt02.inout;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.PrintStream;

import java.io.UnsupportedEncodingException;

 

public class Test05 {

public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {

 

// 通过打印流写入数据到一个文件(gbk)

/*File file = new File("d:\\javatest\\m.txt");

PrintStream ps = new PrintStream(file);

ps.write('a');

ps.write('b');

 

ps.close();*/

 

 

// 通过打印流写入一个utf8编码的文件

File file = new File("d:\\javatest\\m1.txt");

PrintStream ps = new PrintStream(file,"utf8");

ps.println("abc中国");

 

ps.close();

 

}

}

 

 

需要flushPrintStream

package cn.sxt02.inout;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.PrintStream;

import java.io.UnsupportedEncodingException;

 

public class Test04 {

public static void main(String[] args) {

 

 

PrintStream ps = System.out;

ps.write('a');

ps.write('b');

 

ps.flush();

 

}

}

 

PrintStream称为打印字节流继承于OutputStream,之前已经知道OutputStream写入文件时不需要flushPrintStream目的地是显示器PrintStream内部有个缓冲区,专门用于缓冲待输出的字节结合显示器工作原理,当需要显示器显示待打印的字节,需要手动调用flush方法,此时显示器才解码后显示。

 

测试自动刷新(C)

package cn.sxt02.inout;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.PrintStream;

import java.io.UnsupportedEncodingException;

 

public class Test04 {

public static void main(String[] args) throws IOException {

 

PrintStream ps = System.out;

/*ps.write('a');

ps.write('b');*/

 

// 自动调用flush方法

/*byte[] buf = {'a','b'};

ps.write(buf);*/

 

// 自动调用flush方法

/*ps.write('a');

ps.write('b');

ps.write('\n');*/

 

// 自动调用flush方法

ps.println("ab");

 

// sps.flush();

 

}

}

 

 

1.7 字符打印流

PrintWriter 专门用于向自定目的地(显示器、文件、浏览器)大量字符。继承Writer除了write(char)/write(char[] cbuf),提供了特有的print/println方法用于输出各位数据类型的字符。

public class Test01 {

public static void main(String[] args) {

 

// 字符输出流

PrintWriter pw = new PrintWriter(System.out);

pw.println("hello");

pw.println("中国");

 

pw.flush();

 

pw.close();

}

}

 

1.8 序列化

(程序)内存中的数据保存到硬盘的过程就是序列化,也称为数据持久化。

我们把硬盘中的数据再次读取到内存中时,这个过程就是反序列化。

 

1.8.1 Serializable接口

 

自定义类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化

 

需求:一个对象序列化到d:\\javatest\\n1.txt

 

package cn.sxt04.serializable;

 

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectOutputStream;

 

public class Test01 {

public static void main(String[] args) throws IOException {

 

User user = new User("001", "二狗", "123", 20);

 

/**

 * 思路:

 * 序列化:把对象个各个属性按照有规律的格式拼接成字符串,把字符串写入文件。

 * 反序列化:把文件中的字符串读取为内存中,按序列化格式把字符串拆开得到很多属性值,然后初始化对象。

 */

// String info = user.getId()+"-"+user.getName()+"-"+user.getPwd()+"-"+user.getAge();

// System.out.println(info);

 

File file = new File("d:\\javatest\\n1.sxt");

FileOutputStream out = new FileOutputStream(file);

ObjectOutputStream oos = new ObjectOutputStream(out);

 

oos.writeObject(user);

 

oos.close();

out.close();

 

}

}

 

 

需求:把刚在序列化的对象反序列化

package cn.sxt04.serializable;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

 

public class Test02 {

public static void main(String[] args) throws IOException, ClassNotFoundException {

 

 

File file = new File("d:\\javatest\\n1.sxt");

 

FileInputStream in = new FileInputStream(file);

ObjectInputStream ois = new ObjectInputStream(in);

 

User user = (User) ois.readObject();

System.out.println(user);

 

}

}

 

1.8.2 序列号

程序在升级过程中对源代码进行修改新代码对之前的序列化文件进行反序列化存在一个InvalidClassException异常

Exception in thread "main" java.io.InvalidClassException: cn.sxt04.serializable.User; local class incompatible: stream classdesc serialVersionUID = 4281284299154400224, local class serialVersionUID = 8687762707351138232

at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1876)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)

at cn.sxt04.serializable.Test02.main(Test02.java:19)

 

 

如何解决?

始终保持本地类和序列化中文件的类的版本号一致。

 

[1]默认版本号,永远是1L

[2]手动根据的信息(属性、方法)生成一串数字。

 

版本工作原理

如果自定义类没有添加任何序列化版本号,jvm自动添加一个序列化版本号,当修改源代码时,jvm自动升级序列化版本号,此时导致和序列化到本地文件的类版本号不一致反序列化必将失败,抛出InvalidClassException异常

 

1.8.3 transient 关键字

序列化过程中,存在一些字段序列化没有意义或一些敏感自动不许序列化,可以使用transient修饰

 

public class User implements Serializable {

/**

 *

 */

private static final long serialVersionUID = 1L;

private String id;

private String name;

private transient String pwd;

private int age;

private String phone;

 

其他

DataInputStream/DataOutputStream

posted @ 2019-05-23 20:47  沈振辉  阅读(168)  评论(0编辑  收藏  举报