Java之IO流

生活中,流有水流,河流等,它们是通过水管或者是河渠等管道或通道按一定方向流动形成的。

Java中的IO流和现实中的流很像,也是通过特定的管道,数据按一定的方向流动形成了IO流。这也是我们今天主要讲的内容。

Java中IO流是实现输入,输出的基础,可以方便的实现数据的输入和输出。

Java的IO流中常用到的一些类有,File,InputStream,OutputStream,FileInputStream,FileOutputStream,Reader,Writer,FileReader,FileWriter,BufferedReader,BufferedWriter

1.1 File类

Filejava中表示(路径的)文件或者目录。

 

1.1.1 File常用属性和方法

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 // 给定路径创建File对象
 6 
 7 // File file = new File("D:"+File.separator+"javatest"+File.separator+"a.txt");
 8 
 9 File file = new File("d:\\javatest\\b.mp3");
10 
11 System.out.println(file);
12 
13  
14 
15 // 文件基本属性
16 
17 System.out.println(file.canExecute());
18 
19 System.out.println(file.canRead());
20 
21 System.out.println(file.canWrite());
22 
23  
24 
25 // 文件的创建、删除
26 
27 if(!file.exists()) {
28 
29  
30 
31 boolean r;
32 
33 try {
34 
35 r = file.createNewFile();
36 
37 if(r) {
38 
39 System.out.println("文件创建成功");
40 
41 }
42 
43 } catch (IOException e) {
44 
45 e.printStackTrace();
46 
47 }
48 
49 }
50 
51  
52 
53 // 删除文件
54 
55 file.delete();
56 
57 }

创建文件时会抛出检查时异常IOException

1.1.2 File的路径相关

 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5  File file = new File("d:\\javatest\\a");
 6 
 7 // File file = new File("a.txt");
 8 
 9  
10 
11 // 获取file的绝对路径
12 
13 System.out.println(file.getAbsolutePath());
14 
15 // 获取file的创建时的路径字符串
16 
17 System.out.println(file.getPath());
18 
19 // 获取文件或者目录的名字
20 
21 System.out.println(file.getName());
22 
23 // 获取文件或者目录的父目录
24 
25 System.out.println(file.getParent());
26 
27  
28 
29 }

注意:如果file是相对路径,相对路径的当前路径是工程目录(java17)

1.1.3 目录的创建

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5  File file = new File("d:\\javatest\\c\\d\\e");
 6 
 7  
 8 
 9  if(!file.exists()) {
10 
11  boolean r;
12 
13  
14 
15 try {
16 
17 // 一次只能创建一个目录
18 
19 // r = file.mkdir();
20 
21 r = file.mkdirs();
22 
23 if(r) {
24 
25 System.out.println("目录创建成功");
26 
27 }
28 
29 } catch (Exception e) {
30 
31 e.printStackTrace();
32 
33 }
34 
35  
36 
37  }
38 
39 }

1.1.4 目录的遍历

list():返回一个file表示的目录中的子目录或者文件,字符串数组类型

listFiles():返回一个file表示的目录中的子目录或者文件File数组类型

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 // 需求:遍历d:\javatest目录
 6 
 7 // list()
 8 
 9 File file =  new File("d:\\javatest");
10 
11  
12 
13  
14 
15 /*
16 
17 String[] list = file.list();
18 
19  
20 
21 for (String str : list) {
22 
23 System.out.print(str);
24 
25 File f = new File(file.getPath()+"\\"+str);
26 
27 if(f.isDirectory()) {
28 
29 System.out.println(" 目录");
30 
31 }else {
32 
33 System.out.println(" 文件");
34 
35 }
36 
37 }*/
38 
39  
40 
41  
42 
43 // listFiles();
44 
45 File[] listFiles = file.listFiles();
46 
47 for (File f : listFiles) {
48 
49 System.out.print(f.getName());
50 
51 if(f.isDirectory()) {
52 
53 System.out.println(" 目录");
54 
55 }else {
56 
57 System.out.println(" 文件");
58 
59 }
60 
61 }
62 
63 }

 练习:

 

1.2 IO

1.2.1 

(stream):是一连串流动的数据(字节、字符),先进先出的方式发送的信息的通道中。

1.2.2 输入流和输出流

输入流

数据从源数据源程序的过程称为输入流可以理解为从源数据源读取数据到程序的过程

 

输出

数据从程序流到目的地的过程称为输出流。可以理解为把数据程序写入目的地的过程

 

数据源一般指提供数据的原始媒介,一般常见有文件、数据库、云端其他硬件等能提供数据的媒介。

 

1.2.3 的分类

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

按照处理单元分为字节流和字符流

按照功能分为节点流转换流。

 

 

1.3 InputStream/OutputStream

InputStream 是所有字节输入流抽象父类提供了

read 读取一个字节

read(byte[] buf) 读取一定量的字节到缓冲区数组 buf

 

OutputStream 所有字节输出流的抽象父类,提供了

write() 写入一个字节

write(byte[] buf) 写入一定量的字节到输出流

 

FileInputStream 文件字节输入流专门用于从文件中读取字节到程序内存中。

FileOutputStream 文件字节输出流,专门用于从内存中写入字节到文件中。

 

需求:文件读取一个字节

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5 // 需求:读取一个文件中的一个字节
 6 
 7 File file = new File("d:\\javatest\\a.txt");
 8 
 9  
10 
11 // 【1】创建管道
12 
13 FileInputStream in = null;
14 
15  
16 
17 try {
18 
19 in = new FileInputStream(file);
20 
21  
22 
23 // 【2】从管道读取一个字节
24 
25 /*
26 
27 int t;
28 
29 t = in.read();
30 
31 t = in.read();
32 
33 t = in.read();
34 
35 t = in.read();
36 
37 */
38 
39 // System.out.println(t);
40 
41  
42 
43 // 循环读取一个字节
44 
45 int t;
46 
47 StringBuilder sb = new StringBuilder();
48 
49 while( (t=in.read()) != -1 ) {
50 
51 sb.append((char)t);
52 
53 }
54 
55  
56 
57 System.out.println(sb.toString());
58 
59  
60 
61  
62 
63  
64 
65 } catch (FileNotFoundException e) {
66 
67 e.printStackTrace();
68 
69 } catch(IOException e) {
70 
71 e.printStackTrace();
72 
73 }
74 
75  
76 
77 // 【3】关闭流管道
78 
79 try {
80 
81 in.close();
82 
83 } catch (IOException e) {
84 
85 e.printStackTrace();
86 
87 }
88 
89 }

 

 

一次读取多个字节

  1 public static void main(String[] args) {
  2 
  3  
  4 
  5 // 需求:一次读取多个字节
  6 
  7 File file = new File("d:\\javatest\\a.txt");
  8 
  9  
 10 
 11 // 【1】创建管道
 12 
 13 FileInputStream in = null;
 14 
 15  
 16 
 17 try {
 18 
 19 in = new FileInputStream(file);
 20 
 21  
 22 
 23 // 【2】从管道读取多个字节到缓冲区
 24 
 25 /*
 26 
 27 byte[] buf = new byte[5];
 28 
 29 int len;
 30 
 31 len = in.read(buf);
 32 
 33 len = in.read(buf);
 34 
 35 len = in.read(buf);
 36 
 37 len = in.read(buf);
 38 
 39  
 40 
 41 for(byte b:buf) {
 42 
 43 System.out.print((char)b+"\t");
 44 
 45 }
 46 
 47 System.out.println(len);
 48 
 49 */
 50 
 51  
 52 
 53 // 通过循环读取文件
 54 
 55 byte[] buf = new byte[5];
 56 
 57 int len;
 58 
 59 StringBuilder sb = new StringBuilder();
 60 
 61 while( (len=in.read(buf)) != -1 ) {
 62 
 63 // 读取的内容是原始二进制流,需要根据编码的字符集解码成对于字符
 64 
 65 String str = new String(buf,0,len);
 66 
 67 sb.append(str);
 68 
 69 }
 70 
 71 System.out.println(sb.toString());
 72 
 73  
 74 
 75  
 76 
 77  
 78 
 79  
 80 
 81 } catch (FileNotFoundException e) {
 82 
 83 e.printStackTrace();
 84 
 85 } catch(IOException e) {
 86 
 87 e.printStackTrace();
 88 
 89 }
 90 
 91  
 92 
 93 // 【3】关闭流管道
 94 
 95 try {
 96 
 97 in.close();
 98 
 99 } catch (IOException e) {
100 
101 e.printStackTrace();
102 
103 }
104 
105 }

 

 

需求:按照指定编码写入文件

 

 1 public static void main(String[] args) {
 2 
 3  
 4 
 5  
 6 
 7 File file = new File("d:\\javatest\\c.txt");
 8 
 9  
10 
11 FileOutputStream out = null;
12 
13  
14 
15 try {
16 
17 // 【1】创建输出流管道
18 
19 out = new FileOutputStream(file);
20 
21  
22 
23 // 【2】写入数据到管道中
24 
25 // 一次写入一个字节
26 
27 /*
28 
29 out.write(97);
30 
31 out.write(98);
32 
33 out.write(99);
34 
35 */
36 
37  
38 
39 // 一次写入多个字节
40 
41 String str = "hello world";
42 
43 // gbk
44 
45 /*
46 
47 byte[] buf = str.getBytes();
48 
49 out.write(buf);
50 
51 */
52 
53  
54 
55 byte[] buf = str.getBytes("UTF-8");
56 
57 out.write(buf);
58 
59  
60 
61 System.out.println("写入完成!");
62 
63  
64 
65 } catch (FileNotFoundException e) {
66 
67 e.printStackTrace();
68 
69 } catch (IOException e) {
70 
71 e.printStackTrace();
72 
73 }
74 
75  
76 
77 // 【3】关闭流
78 
79 try {
80 
81 out.close();
82 
83 } catch (IOException e) {
84 
85 e.printStackTrace();
86 
87 }
88 
89 }

 

 

 

注意:

[1]字符串写入文件时一定会存在编码问题

[2]使用utf8编码写入文件时,如果不含中文时,win系统会对文件的编码造成误判。

[3] 通过字节流写入文件时,管道写入一个字节,该字节立即写入文件中。

 

总结

InputStream/OutputStream 用于字节的读写。主要用于读取二进制文件(图片、音频、视频),可以读取文件性文件。

 

需求:d:\\javatest\\logo.png 复制到工程目录中并显示复制进度。

 1 public static void main(String[] args) throws FileNotFoundException,IOException {
 2 
 3  
 4 
 5  
 6 
 7 File oriFile = new File("d:\\javatest\\logo.jpg");
 8 
 9 File toFile = new File("logo.jpg");
10 
11  
12 
13 long totalLen = oriFile.length(); // 文件大小
14 
15 long cpyedLen = 0; // 已复制完成的大小
16 
17 float progress = 0.0f;
18 
19  
20 
21 FileInputStream in = new FileInputStream(oriFile);
22 
23 FileOutputStream out = new FileOutputStream(toFile);
24 
25  
26 
27 // 一次读取1kb
28 
29 byte[] buf = new byte[512];
30 
31 int len;
32 
33 while( (len=in.read(buf)) != -1) {
34 
35 out.write(buf, 0, len);
36 
37 cpyedLen += len;
38 
39 progress = cpyedLen*1.0f/totalLen;
40 
41 System.out.println(progress);
42 
43  
44 
45  
46 
47 }
48 
49  
50 
51 in.close();
52 
53 out.close();
54 
55  
56 
57 System.out.println("复制完成!");
58 
59  
60 
61 }

 

 

思考:字节流来读取文本性文件时,按字节读容易造成乱码。此时,能不能按字符来读取。

 

1.4 Reader/Writer

Reader 是字符输入流的抽象父类,提供了

read 一次读取一个字符

read(char[] cbuf) 一次读取多个字符到字符缓冲区cbuf返回长度表示读取的字符个数

 

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

write

write(char[] cbuf)

write(string)

 

FileReader 文件字符输入流,专门用于读取默认字符编码文本性文件。

 

FileWriter 文件字符输出流,专门用于写入默认字符编码的文本性文件。为了提高效率,FileWriter内部存在一个字节缓冲区,用于对待写入的字符进行统一编码字节缓冲区,一定要在关闭流之前,调用flush方法刷新缓冲区。

 

需求:一次读取一个字符/多个字符到cbuf

 1 public static void main(String[] args) throws IOException {
 2 
 3  
 4 
 5 File file = new File("d:\\javatest\\d.txt");
 6 
 7  
 8 
 9 FileReader reader = new FileReader(file);
10 
11  
12 
13 // 【1】一次读取一个字符
14 
15 /*
16 
17 int c;
18 
19 c = reader.read();
20 
21 c = reader.read();
22 
23 c = reader.read();
24 
25 c = reader.read();
26 
27 c = reader.read();
28 
29 System.out.println((char)c);
30 
31 */
32 
33  
34 
35 // 【2】一次读取多个字符到cbuf中
36 
37 /*
38 
39 char[] cbuf = new char[2];
40 
41 int len;
42 
43 len = reader.read(cbuf);
44 
45 len = reader.read(cbuf);
46 
47 len = reader.read(cbuf);
48 
49 len = reader.read(cbuf);
50 
51 System.out.println(Arrays.toString(cbuf));
52 
53 System.out.println(len);
54 
55 */
56 
57  
58 
59 char[] cbuf = new char[2];
60 
61 int len;
62 
63 StringBuilder sb = new StringBuilder();
64 
65 while( (len=reader.read(cbuf)) != -1 ) {
66 
67 sb.append(cbuf,0,len);
68 
69 }
70 
71  
72 
73 System.out.println(sb);
74 
75 }

 

 

需求:写入字符到文件中

 1 public static void main(String[] args) throws IOException {
 2 
 3  
 4 
 5  
 6 
 7 File file = new File("d:\\javatest\\f.txt");
 8 
 9  
10 
11 FileWriter writer = new FileWriter(file);
12 
13  
14 
15 // 【1】一次写入一个字符
16 
17 /*writer.write('中');
18 
19 writer.write('国');*/
20 
21  
22 
23 // 【2】一次写入多个字符
24 
25 /*char[] cbuf = {'h','e','l','l','o','中','国'};
26 
27 writer.write(cbuf);*/
28 
29  
30 
31 // 【3】一次写入一个字符串
32 
33 String str = "hello你好";
34 
35 writer.write(str);
36 
37  
38 
39  
40 
41 // 刷新字节缓冲区
42 
43 writer.flush();
44 
45  
46 
47 // 关闭流通道
48 
49 writer.close();
50 
51  
52 
53 System.out.println("写入完成");
54 
55 }

 

 

思考:如何字符串utf8或者其他编码写入文件?

 

1.5 转换

 

InputStreamReader 继承Reader,是字节流通向字符流的桥梁可以把字节流按照指定编码 解码 成字符流。

 

OutputStreamWriter 继承Writer,是字符流通向字节流的桥梁,可以把字符流按照指定的编码 编码 成字节流。

1.5.1 转换流工作原理

 

 

需求:写入utf8文件

 1 /**
 2 
 3  * 把一个字符串以utf8编码写入文件
 4 
 5  */
 6 
 7 public class Test01 {
 8 
 9 public static void main(String[] args) throws IOException {
10 
11  
12 
13  
14 
15 String str = "hello中国";
16 
17 File file = new File("d:\\javatest\\g.txt");
18 
19  
20 
21 // 【1】创建管道
22 
23 FileOutputStream out = new FileOutputStream(file);
24 
25 OutputStreamWriter writer = new OutputStreamWriter(out, "utf8");
26 
27  
28 
29 // 【2】写入管道
30 
31 writer.write(str);
32 
33  
34 
35 // 【3】刷新缓冲区
36 
37 writer.flush();
38 
39  
40 
41 // 【4】关闭管道
42 
43 out.close();
44 
45 writer.close();
46 
47  
48 
49 System.out.println("写入完成");
50 
51 }
52 
53 }

 

 

需求:读取utf8文件

 1 /**
 2 
 3  * 读取utf8编码的文本文件
 4 
 5  */
 6 
 7 public class Test01 {
 8 
 9 public static void main(String[] args) throws IOException {
10 
11  
12 
13 File file = new File("d:\\javatest\\g.txt");
14 
15  
16 
17 // 【1】建立管道
18 
19 FileInputStream in = new FileInputStream(file);
20 
21 InputStreamReader reader = new InputStreamReader(in, "UTF-8");
22 
23  
24 
25 char[] cbuf = new char[2];
26 
27 int len;
28 
29  
30 
31 StringBuilder sb = new StringBuilder();
32 
33 while( (len=reader.read(cbuf))!=-1 ) {
34 
35 sb.append(cbuf, 0, len);
36 
37 }
38 
39 System.out.println(sb.toString());
40 
41  
42 
43 }
44 
45 }

 

 

注意:

[1]win平台默认的utf8编码的文本性文件带有BOM,java转换流写入的utf8文件不带BOM。所以java读取手动创建的utf8文件会出现一点乱码(?hello中国,?bom导致的)

[2] 一句话:用字符集编码,一定用字符集解码!!

 

思考:

FileReader = InputStreamReader + GBK

 1 package cn.sxt07.outputstreamwriter;
 2 
 3  
 4 
 5 import java.io.File;
 6 
 7 import java.io.FileInputStream;
 8 
 9 import java.io.FileReader;
10 
11 import java.io.IOException;
12 
13 import java.io.InputStreamReader;
14 
15  
16 
17 /**
18 
19  * 读取一个gbk编码的文本性文件
20 
21  */
22 
23 public class Test02 {
24 
25 public static void main(String[] args) throws IOException {
26 
27  
28 
29  
30 
31 File file = new File("d:\\javatest\\f.txt");
32 
33  
34 
35 // 【1】建立管道
36 
37 /*
38 
39  * FileInputStream in = new FileInputStream(file);
40 
41  * InputStreamReader reader =  new InputStreamReader(in, "GBK");
42 
43  */
44 
45  
46 
47 FileReader reader = new FileReader(file);
48 
49  
50 
51 char[] cbuf = new char[2];
52 
53 int len;
54 
55  
56 
57 StringBuilder sb = new StringBuilder();
58 
59 while( (len=reader.read(cbuf))!=-1 ) {
60 
61 sb.append(cbuf, 0, len);
62 
63 }
64 
65  
66 
67 reader.close();
68 
69  
70 
71 System.out.println(sb.toString());
72 
73 }
74 
75 }
76 
77  

 

 

1.6 BufferedReader/BufferedWriter

BufferedReader 继承Reader提供

read

read(char[] cbuf)

readLine() 用于读取一行文本,实现对文本的高效读取。

BufferedReader 初始化时需要一个reader本质BufferedReaderreader的基础上增加readLine()的功能。

 

BufferedWriter继承Writer提供

write

write(char[] cbuf)

write(string)

newline() 写入一个行分隔符。

 

需求:读取一首诗

 1 public static void main(String[] args) throws IOException {
 2 
 3  
 4 
 5 // 按行读取gbk文本性文件
 6 
 7  
 8 
 9 File file = new File("d:\\javatest\\i.txt");
10 
11  
12 
13 // 【1】创建管道
14 
15 FileReader reader = new FileReader(file);
16 
17 BufferedReader br = new BufferedReader(reader);
18 
19  
20 
21 // 【2】读取一行
22 
23 /*
24 
25 String line =  br.readLine();
26 
27 line =  br.readLine();
28 
29 line =  br.readLine();
30 
31 line =  br.readLine();
32 
33 */
34 
35  
36 
37 String line;
38 
39 while( (line=br.readLine()) != null) {
40 
41 System.out.println(line);
42 
43 }
44 
45 }

 

 

需求:gbk编码写入一首诗到文件

 1 public static void main(String[] args) throws IOException {
 2 
 3  
 4 
 5 File file = new File("d:\\javatest\\j.txt");
 6 
 7  
 8 
 9 // 【1】创建gbk管道
10 
11 FileWriter writer = new FileWriter(file);
12 
13 BufferedWriter bw = new BufferedWriter(writer);
14 
15  
16 
17 // 【2】写入一行
18 
19 bw.write("窗前明月光,");
20 
21 bw.newLine();
22 
23  
24 
25 bw.write("疑似地上霜。");
26 
27  
28 
29 // for win
30 
31 // bw.write("\r\n");
32 
33  
34 
35 // for unix/linux/mac
36 
37 // bw.write("\n");
38 
39  
40 
41 bw.write("举头望明月,");
42 
43 bw.newLine();
44 
45  
46 
47 // 【3】flush
48 
49 bw.flush();
50 
51  
52 
53 // 【4】关闭管道
54 
55 bw.close();
56 
57 writer.close();
58 
59 }

 

 

需求:utf8编码高效写入文件

 1 /**
 2 
 3  * 以utf8写入一首诗
 4 
 5  * @author Administrator
 6 
 7  *
 8 
 9  */
10 
11 public class Test02 {
12 
13 public static void main(String[] args) throws IOException {
14 
15  
16 
17 File file = new File("d:\\javatest\\j-utf8.txt");
18 
19  
20 
21 // 【1】创建utf8管道
22 
23 FileOutputStream out = new FileOutputStream(file);
24 
25 OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
26 
27 BufferedWriter bw = new BufferedWriter(writer);
28 
29  
30 
31 // 【2】写入一行
32 
33 bw.write("窗前明月光,");
34 
35 bw.newLine();
36 
37  
38 
39 bw.write("疑似地上霜。");
40 
41  
42 
43 // for win
44 
45 bw.write("\r\n");
46 
47  
48 
49 // for unix/linux/mac
50 
51 // bw.write("\n");
52 
53  
54 
55 bw.write("举头望明月,");
56 
57 bw.newLine();
58 
59  
60 
61 // 【3】flush
62 
63 bw.flush();
64 
65  
66 
67 // 【4】关闭管道
68 
69 bw.close();
70 
71 writer.close();
72 
73 }
74 
75 }

 

posted @ 2019-05-06 22:49  cowbe  阅读(273)  评论(0编辑  收藏  举报