File类的使用

  • File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)

  • File类声明在java.io包下。

  • File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法。

    并未涉及到写入或读取文件内容的操作,如果需要读取或写入文件内容,必须使用IO流来完成。

  • 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的”终点”。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/**
1:如何创建File类的实例:
File(String filePath)

File(String parentPath,String childpath)

File(File parentFile,String childPath)
2:相对路径:相较于某个路径下,指明的路径。
绝对路径:包含盘符在内的文件或文件目录的路径。

3:路径分隔符
windows:\\
unix:/

*/

public class FileTest{

@Test
public void test1(){
// 构造器
File file1 = new File("hello.txt"); // 相对于当前moudle
File file2 = new File("D:\\workspace_idea1\\JavaSenior\\day08\\he.txt");
System.out.println(file1);
System.out.println(file2);

//构造器2:
File file3 = new File("D:\\workspace_idea1","JavaSenior");
System.out.println(file3);

//构造器3:
File file4 = new File(file3,"hi.txt");
System.out.println(file4);
}

/**
public String getAbsolutePath():获取绝对路径
public String getPath() :获取路径
public String getName() :获取名称
public String getParent():获取上层文件目录路径。若无,返回null
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值

如下的两个方法适用于文件目录:
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组

*/

@Test
public void test2(){
File file1 = new File("hello.txt");
File file2 = new File("d:\\io\\hi.txt");

System.out.println(file1.getAbsolutePath());
System.out.println(file1.getPath());
System.out.println(file1.getName());
System.out.println(file1.getParent());
System.out.println(file1.length());
System.out.println(new Date(file1.lastModified()));

System.out.println();

System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());
System.out.println(file2.getName());
System.out.println(file2.getParent());
System.out.println(file2.length());
System.out.println(file2.lastModified());
}

@Test
public void test3(){
File file = new File("D:\\workspace_idea1\\JavaSenior");

String[] list = file.list();
for(String s : list){
System.out.println(s);
}

System.out.println();

File[] files = file.listFiles();
for(File f : files){
System.out.println(f);
}
/**
public boolean renameTo(File dest):把文件重命名为指定的文件路径
比如:file1.renameTo(file2)为例:
要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。
*/

@Test
public void test4(){
File file1 = new File("hello.txt");
File file2 = new File("D:\\io\\hi.txt");

boolean renameTo = file2.renameTo(file1);
System.out.println(renameTo);

}

/**
public boolean isDirectory():判断是否是文件目录
public boolean isFile() :判断是否是文件
public boolean exists() :判断是否存在
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏
*/

@Test
public void test5(){
File file1 = new File("hello.txt");
file1 = new File("hello1.txt");

System.out.println(file1.isDirectory());
System.out.println(file1.isFile());
System.out.println(file1.exists());
System.out.println(file1.canRead());
System.out.println(file1.canWrite());
System.out.println(file1.isHidden());

System.out.println();

File file2 = new File("d:\\io");
file2 = new File("d:\\io1");
System.out.println(file2.isDirectory());
System.out.println(file2.isFile());
System.out.println(file2.exists());
System.out.println(file2.canRead());
System.out.println(file2.canWrite());
System.out.println(file2.isHidden());

}

/**
创建硬盘中对应的文件或文件目录
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs() :创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,一并创建

删除磁盘中的文件或文件目录
public boolean delete():删除文件或者文件夹
删除注意事项:Java中的删除不走回收站。
*/
@Test
public void test6() throws IOException {
File file1 = new File("hi.txt");
if(!file1.exists()){
//文件的创建
file1.createNewFile();
System.out.println("创建成功");
}else{//文件存在
file1.delete();
System.out.println("删除成功");
}


}
@Test
public void test7(){
//文件目录的创建
File file1 = new File("d:\\io\\io1\\io3");

boolean mkdir = file1.mkdir();
if(mkdir){
System.out.println("创建成功1");
}

File file2 = new File("d:\\io\\io1\\io4");

boolean mkdir1 = file2.mkdirs();
if(mkdir1){
System.out.println("创建成功2");
}
//要想删除成功,io4文件目录下不能有子目录或文件
File file3 = new File("D:\\io\\io1\\io4");
file3 = new File("D:\\io\\io1");
System.out.println(file3.delete());
}

}

流的分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
一、流的分类:

1.操作数据单位:字节流、字符流

2.数据的流向:输入流、输出流

3.流的角色:节点流、处理流

二、流的体系结构

抽象基类 节点流(或文件流) 缓冲流(处理流的一种)

InputStream FileInputStream (read(byte[] buffer)) BufferedInputStream (read(byte[] buffer))

OutputStream FileOutputStream (write(byte[] buffer,0,len) BufferedOutputStream (write(byte[]buffer,0,len) / flush()

Reader FileReader (read(char[] cbuf)) BufferedReader (read(char[] cbuf) / readLine())

Writer FileWriter (write(char[] cbuf,0,len) BufferedWriter (write(char[] cbuf,0,len) / flush()

字节流与字符流的区别:

  • FileInputStream 和 FileOutputStream 可以完成所有格式文件的赋值。
  • FileReader 和 FileWriter 只可以完成文本文件的复制,却无法完成视频格式文件的复制。
  • 因为字节是不需要解码和编码的,将字节转化为字符才存在解码和编码的问题。
  • 字节流可以从所有格式的设备中读写数据,但字符流只能从文本格式的设备中读写数据。

Demo

处理文本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.*;

public class TestIO
{
public static void main(String[] args) throws Exception
{
FileReader fr = new FileReader("C:\\Users\\DELL\\Desktop\\TestIO.java"); // FileReader 文件输入字符流;
int ch;
int cnt = 0;


ch = fr.read();
while (-1 != ch)
{
++cnt;
System.out.printf("%c", (char)ch);
ch = fr.read();
}
System.out.printf("该文件字符的个数是:%d\n", cnt);
fr.close();
}

}

--------------------------------------------------------------------------------------------------------
/**
本程序证明了:
如果通过一个字节流把文本文件的内容输出到显示器上,当输出汉字时就会出现乱码
因为文字要用字符流处理才能在显示器上输出正确的内容。
*/

import java.io.*;

public class TestIO_2
{
public static void main(String[] args) throws Exception
{
FileInputStream fr = new FileInputStream("C:\\Users\\DELL\\Desktop\\TestIO.java"); // FileInputStream 文件输入字节流
int ch;
int cnt = 0;

ch = fr.read();
while (-1 != ch)
{
++cnt;
System.out.printf("%c", (char)ch);
ch = fr.read();
}
System.out.printf("该文件字符的个数是:%d\n", cnt);
fr.close();
}
}

处理非文本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**

通过字符流完成文本文件的复制

*/

import java.io.*;

public class TestFileReaderWriterCopy
{
public static void main(String[] args) throws Exception
{
FileReader fr = new FileReader("D:\\share\\S5\\di-20 流\\TestFileReaderWriterCopy.java");
FileWriter fw = new FileWriter("d:/zhangsan.haha");
int ch;


ch = fr.read();
while (-1 != ch)
{
fw.write(ch);
ch = fr.read();
}
fw.flush();

fr.close();
fw.close();
}

}

----------------------------------------------------------------------------------------------------------
/**
本程序证明了:
通过字符流无法完成非文本文件的复制
或者说:
字符流只能处理文本文件
不能处理非文本文件

*/

import java.io.*;

public class TestFileReaderWriterCopy_2
{
public static void main(String[] args) throws Exception
{
FileReader fr = new FileReader("E:\\IBM教学\\java\\lesson_io\\柯南.mp3");
FileWriter fw = new FileWriter("d:/xiuyi.xixi");
int ch;

ch = fr.read();
while (-1 != ch)
{
fw.write(ch);
ch = fr.read();
}
fw.flush();

fr.close();
fw.close();
}
}

File Reader Writer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
public class FileReaderWriterTest {

public static void main(String[] args) {
File file = new File("hello.txt");//相较于当前工程
System.out.println(file.getAbsolutePath());

File file1 = new File("day09\\hello.txt");
System.out.println(file1.getAbsolutePath());
}

/*
将day09下的hello.txt文件内容读入程序中,并输出到控制台

说明点:
1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
2. 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
3. 读入的文件一定要存在,否则就会报FileNotFoundException。

*/
@Test
public void testFileReader(){
FileReader fr = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("hello.txt");//相较于当前Module
//2.提供具体的流
fr = new FileReader(file);

//3.数据的读入
//read():返回读入的一个字符。如果达到文件末尾,返回-1
//方式一:

// int data = fr.read();
// while(data != -1){
// System.out.print((char)data);
// data = fr.read();
// }

//方式二:语法上针对于方式一的修改
int data;
while((data = fr.read()) != -1){
System.out.print((char)data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作

// try {
// if(fr != null)
// fr.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
//或
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}

//对read()操作升级:使用read的重载方法
@Test
public void testFileReader1() {
FileReader fr = null;
try {
//1.File类的实例化
File file = new File("hello.txt");

//2.FileReader流的实例化
fr = new FileReader(file);

//3.读入的操作
//read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){
//方式一:
//错误的写法

// for(int i = 0;i < cbuf.length;i++){
// System.out.print(cbuf[i]);
// }
//正确的写法
// for(int i = 0;i < len;i++){
// System.out.print(cbuf[i]);
// }
//方式二:
//错误的写法,对应着方式一的错误的写法
// String str = new String(cbuf);
// System.out.print(str);
//正确的写法
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null){
//4.资源的关闭
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

}
/*
从内存中写出数据到硬盘的文件里。

说明:
1. 输出操作,对应的File可以不存在的。并不会报异常
2.
File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
File对应的硬盘中的文件如果存在:
如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容

*/
@Test
public void testFileWriter() {
FileWriter fw = null;
try {
//1.提供File类的对象,指明写出到的文件
File file = new File("hello1.txt");

//2.提供FileWriter的对象,用于数据的写出
fw = new FileWriter(file,false);

//3.写出的操作
fw.write("I have a dream!\n");
fw.write("you need to have a dream!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流资源的关闭
if(fw != null){

try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


}

@Test
public void testFileReaderFileWriter() {
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File destFile = new File("hello2.txt");

//不能使用字符流来处理图片等字节数据

// File srcFile = new File("爱情与友情.jpg");
// File destFile = new File("爱情与友情1.jpg");


//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);


//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while((len = fr.read(cbuf)) != -1){
//每次写出len个字符
fw.write(cbuf,0,len);

}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源
//方式一:

// try {
// if(fw != null)
// fw.close();
// } catch (IOException e) {
// e.printStackTrace();
// }finally{
// try {
// if(fr != null)
// fr.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//方式二:
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}

try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}

}

}

}

缓冲流

  • 缓冲流就是带有缓冲区的输入输出流
  • 缓冲流可以i显著的减少我们对IO访问的次数,保护我们的硬盘!
  • 缓冲流本身就是处理流(处理流也称包裹流),缓冲流必须要依附于节点流(节点流也称原始流)
  • 处理流是包裹在原始节点流上的流,相当于包括在管道上的管道!

包裹流

我们只有

  • BufferedInputStream
  • BufferedOutputStream类
  • BufferedWriter
  • BufferedReader

没有

  • BufferedStream
  • BufferedFileInputStream(但有FileInputStream)
  • BufferedFileOutoutStream(但有FileOutputStream)
  • BufferedFileReader(但有FileReader)
  • BufferedFileWriter(但有FileWriter)

所以四个流都是包裹流。

BufferReader 和 BufferWriter

  • Reader FileReader InputStream FileInputStream

    BufferedInputStream 流中都没有 readLine 方法

  • DataInputStream 流中有 readLine 方法,但已经被标记为过时。

  • BufferedReader 流中有 readLine 方法,并且该方法是可以正确使用的。

  • BufferedReader 流中有 readLine 是个非常有用的方法,BufferedReader 是要经常使用的流

  • 利用BufferedReader 和 BufferedWriter 可以提高读写文本文件内容的速度。

完成非文本文件的copy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**

本程序证明了:
通过字节流可以完成音频格式文件的复制
实际上我们通过字节流可以完成任意格式文件的复制

但本程序有个缺点:
没有缓冲区, 处理速度慢

可以参考对比"TestInputStreamOutputStreamCopy_3.java"

*/

import java.io.*;

public class TestInputStreamOutputStreamCopy
{
public static void main(String[] args) throws Exception
{
FileInputStream fr = new FileInputStream("E:\\IBM教学\\java\\lesson_io\\柯南.mp3");
FileOutputStream fw = new FileOutputStream("d:/xiuyi.xixi");
int ch;


ch = fr.read();
while (-1 != ch)
{
fw.write(ch);
ch = fr.read();
}
fw.flush();

fr.close();
fw.close();
}

}

---------------------------------------------------------------------------------------------------------
/**
本程序证明了:
通过字节流可以完成图像文件的复制
实际上我们通过字节流可以完成任意格式文件的复制--->对于文本文件,如果要在操作过程中进行读取,会出现乱码,但如果只是进行完全copy过后再读取,那么字节流是可以胜任的。

*/

import java.io.*;

public class TestInputStreamOutputStreamCopy_2
{
public static void main(String[] args) throws Exception
{
FileInputStream fr = new FileInputStream("C:\\1.jpg");
FileOutputStream fw = new FileOutputStream("d:/xiuyi.xixi");
int ch;

ch = fr.read();
while (-1 != ch)
{
fw.write(ch);
ch = fr.read();
}
fw.flush();

fr.close();
fw.close();
}
}

---------------------------------------------------------------------------------------------------------

/**
本程序证明了:
带缓冲区的字节流处理文件的速度要快于不带缓冲区的字节流处理文件的速度

可以参考对比"TestInputStreamOutputStreamCopy.java"
*/

import java.io.*;

public class TestInputStreamOutputStreamCopy_3
{
public static void main(String[] args) throws Exception
{
BufferedInputStream bis = new BufferedInputStream( new FileInputStream("E:\\IBM教学\\java\\lesson_io\\柯南.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:/xiuyi.xixi"));
byte[] buf = new byte[1024];
int len;

len = bis.read(buf);
while (-1 != len)
{
bos.write(buf, 0, len);
len = bis.read(buf);
}
bos.flush();

bos.close();
bis.close();
}
}

利用 BufferedReader 和 BufferedWriter 完成文本文件的复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.io.*;

public class TestBufferedReaderWriterCopy
{
public static void main(String[] args)
{
BufferedReader br = null;
BufferedWriter bw = null;


try
{
br = new BufferedReader(
new FileReader("D:\\share\\S5\\di-20 流\\TestBufferedReaderWriterCopy.java")
);
bw = new BufferedWriter(
new FileWriter("d:/share/Writer.txt")
);
String str = null;

while (null != (str=br.readLine())) //br.readLine()读取一行字符,但会将读取的换行符自动丢弃,即返回的String对象中并不包括换行符
{
bw.write(str);
bw.newLine(); //写入一个换行符 这行不能省略
}
bw.flush();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
System.exit(-1);
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}
finally
{
try
{
bw.close();
br.close();
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}
}
}

}

转换流

  • 转换流提供了在字节流和字符流之间的转换
  • javaAPI提供了两个转换流:
    • InputStreamReader:将InputStream转换为Reader。
    • OutputStreamWriter:将Writer转换为OutputStream。
  • 字节流中的数据都是字符时,转成字符流操作更高效。
  • 很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**

处理流之二:转换流的使用
1.转换流:属于字符流
InputStreamReader:将一个字节的输入流转换为字符的输入流
OutputStreamWriter:将一个字符的输出流转换为字节的输出流

2.作用:提供字节流与字符流之间的转换

3. 解码:字节、字节数组 --->字符数组、字符串
编码:字符数组、字符串 ---> 字节、字节数组


4.字符集
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。最多两个字节编码所有字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。

*/
public class InputStreamReaderTest {

/*
此时处理异常的话,仍然应该使用try-catch-finally
InputStreamReader的使用,实现字节的输入流到字符的输入流的转换
*/

@Test
public void test1() throws IOException {

FileInputStream fis = new FileInputStream("dbcp.txt");

// InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
//参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");//使用系统默认的字符集

char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.print(str);
}

isr.close();

}

/*
此时处理异常的话,仍然应该使用try-catch-finally

综合使用InputStreamReader和OutputStreamWriter
*/
@Test
public void test2() throws Exception {
//1.造文件、造流
File file1 = new File("dbcp.txt");
File file2 = new File("dbcp_gbk.txt");

FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);

InputStreamReader isr = new InputStreamReader(fis,"utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");

//2.读写过程
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}

//3.关闭资源
isr.close();
osw.close();


}
}

--------------------------------------------------------------------------------------------------------

/*
如何将键盘输入的字符组成字符串直接赋给String 对象

预备知识:
--------------------------------
Reader FileReader InputStream FileInputStream BufferedInputStream
流中都没有 readLine 方法
DataInputStream 流中有 readLine方法,但已经 被标记为过时
BufferedReader 流中有readLine方法,并且该方法是可以正确被使用的
--------------------------------
*/

import java.io.*;

public class TestStringInput
{
public static void main(String[] args)
{
String str = null;
BufferedReader br = new BufferedReader ( //21行
new InputStreamReader(System.in)
); //23行 查API:从21行到23行的代码是不会抛出任何异常的

try
{
str = br.readLine(); //会抛出IOException异常
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}

System.out.println("str = " + str);
try
{
br.close(); //会抛出IOException异常
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}
}
}
/*
在JDK 1.6中的运行结果是:
--------------------------------
sadd行政村123Asd?asd撒旦
str = sadd行政村123Asd?asd撒旦
--------------------------------
*/

其它流

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/**

* 其他流的使用

* 1.标准的输入、输出流

* 2.打印流

* 3.数据流

*/

public class OtherStreamTest {

/*
1.标准的输入、输出流
1.1
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
1.2
System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。

1.3练习:
从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,
直至当输入“e”或者“exit”时,退出程序。

方法一:使用Scanner实现,调用next()返回一个字符串
方法二:使用System.in实现。System.in ---> 转换流 ---> BufferedReader的readLine()

*/

public static void main(String[] args) {
BufferedReader br = null;
try {
InputStreamReader isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);

while (true) {
System.out.println("请输入字符串:");
String data = br.readLine();
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
System.out.println("程序结束");
break;
}

String upperCase = data.toUpperCase();
System.out.println(upperCase);

}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

}

/*

2. 打印流:PrintStream 和PrintWriter

2.1 提供了一系列重载的print() 和 println()
2.2 练习:



*/

@Test
public void test2() {
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
ps = new PrintStream(fos, true);
if (ps != null) {// 把标准输出流(控制台输出)改成文件
System.setOut(ps);
}


for (int i = 0; i <= 255; i++) { // 输出ASCII字符
System.out.print((char) i);
if (i % 50 == 0) { // 每50个数据一行
System.out.println(); // 换行
}
}


} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}

}

/*
3. 数据流
3.1 DataInputStream 和 DataOutputStream
3.2 作用:用于读取或写出基本数据类型的变量或字符串

练习:将内存中的字符串、基本数据类型的变量写出到文件中。

注意:处理异常的话,仍然应该使用try-catch-finally.
*/
@Test
public void test3() throws IOException {
//1.
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
//2.
dos.writeUTF("刘建辰");
dos.flush();//刷新操作,将内存中的数据写入文件
dos.writeInt(23);
dos.flush();
dos.writeBoolean(true);
dos.flush();
//3.
dos.close();


}
/*
将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。

注意点:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!

*/
@Test
public void test4() throws IOException {
//1.
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
//2.
String name = dis.readUTF();
int age = dis.readInt();
boolean isMale = dis.readBoolean();

System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("isMale = " + isMale);

//3.
dis.close();

}

}

ReadLine与回车符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.io.*;

/* readLine()与 回车符 的问题
如果直接输入回车的话,则:
1: br.readLine()会丢弃回车符,而不是返回回车符,即br.readLine()遇到回车符时终止读取,并且
会把读取到的回车符自动丢弃掉。


2:br.readLine()返回的时""而不是null,“”表示空字符串,null表示空指针,空指针就是空地址,空地址就是
不指向任何存储单元的意思。

*/

public class TestBuffered{
public static void main(String[] args) throws Exception{
String str = "zhangsan";
System.out.println("str = " + str);


BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
str = br.readLine(); //如果字节输入回车的话,str的值就会变成空字符串

System.out.println("------------");
System.out.println(str + "123");
System.out.println(str.equals("")); //true
System.out.println(str == null); //false
}

}

对象的序列化

  • 所序列化是指:把一个Object对象直接转换为字节流,然后把这个字节流直接写入本地硬盘或网络中。
  • 如果要想把某个对象序列化,则必须实现Serializable接口。
  • Serializable 接口中并没有任何方法,该接口被称为标记接口,如果一个类实现了 Seralizable 接口,潜在含义就是告诉编译器这个类是允许被序列化的,如果程序中存在序列化该对象的Code,编译器就会自动进行相应的处理已完成该对象的序列化,如果该对象没有实现Serializable接口,程序中却存在该对象被序列化的代码,编译器编译是会报错。
  • 在java中 transient 修饰的成员变量在对象序列化时不被序列化。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import java.io.*;

public class TestObjectIO
{
public static void main(String[] args)
{
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
Student ss = new Student("zhansan", 1000, 88.8f); //注意88.8f不能改为88.8
Student ss2 = null;


try
{
FileOutputStream fos = new FileOutputStream("d:/share/java/ObjectOut.txt");
oos = new ObjectOutputStream(fos);
oos.writeObject(ss);

ois = new ObjectInputStream(new FileInputStream("d:/share/java/ObjectOut.txt"));
ss2 = (Student)ois.readObject(); //(Student)不能省 ois.readObject();如果ois中的某个成员是transient,则该成员是不会被读取的,因为该成员不会被保存,何来读取之说?!

System.out.println("ss2.sname = " + ss2.sname);
System.out.println("ss2.sid = " + ss2.sid);
System.out.println("ss2.sscore = " + ss2.sscore);
}
catch (FileNotFoundException e)
{
System.out.println("文件没有找到!");
System.exit(-1);
}
catch (Exception e)
{
e.printStackTrace();
System.exit(-1);
}
finally
{
try
{
oos.close();
ois.close();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(-1);
}
}
}

}

class Student implements Serializable //如果将implements Serializable 注释掉,则程序编译时就会报错 Serializable是空接口,起标识作用。
{
public String sname = null;
public int sid = 0;
transient public float sscore = 0; //表示sscore成员不能被序列化,所谓不能被序列化就是指:“该成员调用ObjectOutputStream 的writeOnbject()时不会被保存,调用ObjectInputStream的readObject()方法时不会被读取”


public Student(String name, int id, float score)
{
this.sname = name;
this.sid = id;
this.sscore = score;
}

}

Print流与Object流

Print流:

  • Print流只有输出,没有输入
  • 分类
    • PrintWriter 输出字符
    • PrintStream 输出字节

Print流的由来:

  • Writer 的 writer 方法可以写入
    • 一个字符
    • 一个字符数组
    • 一个字符数组一部分
    • 一个字符串
    • 一个字符的一部分
  • OutputStream 的writer 方法可以写入:
    • 一个字节
    • 一个字节数组
    • 一个字节数组的一部分
  • DataOutputStream 流可以写入:
    • 一个字节
    • 一个字节数组(继承自OutputStream)
    • 一个字节数组的一部分
    • 所有的基本类型数据的二进制代码
      • 如writerDouble(8.8);写入的是8.8的二进制代码,共占8个字节。
  • PrintStream 流的print可以写入:
    • 所有基本类型数据的字符串形式表示:
      • 如print(8.8);写入的是’8’’.’’8’这三个字符,共占3个字节。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
DataOutputStream 中的 writeXXX(data)方法

PrintStream 中的 println(data)的区别


总结:
DataOutputStream 中的 writeXXX(data)方法是把data在内存中的二进制数据写入文件
PrintStream 中的 println(data)写出的是该数据的格式化后的字符串

*/

import java.io.*;

public class TestPrintStream_1
{
public static void main(String[] args) throws Exception
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/share/kk.txt"));
dos.writeLong(12345); //实际写入文件的是00 00 00 00 00 00 30 39
dos.close();
System.out.printf("%#X\n", 12345);


PrintStream ps = new PrintStream(new FileOutputStream("d:/share/kk2.txt"), true);
ps.println(12345); //实际写入文件的是'1' '2' '3' '4' '5'
ps.close();
}

}

标准输入输出的重定向

  • 编程实现将键盘输入到的数据输入A文件中,如果输入有误,则把出错信息输入到B文件中。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**

功能: 将键盘输入的数据输入A文件中,如果输入有误,
则把出错信息输出到B文件中

标准输入输出流的重定向

*/

import java.io.*;
import java.util.*;

public class TestSetOutErr
{
public static void main(String[] args)
{
PrintStream psOut = null;
PrintStream psError = null;
Scanner sc = null;



try
{
psOut = new PrintStream("d:/Out.txt");
psError = new PrintStream("d:/error.txt");
sc = new Scanner(System.in);
int num;
System.setOut(psOut);
System.setErr(psError);

while (true)
{
num = sc.nextInt();
System.out.println(num);
}
}
catch (Exception e)
{
System.err.println("出错的信息是:"); //不可以写成System.out.println("出错的信息是:");
e.printStackTrace(); //e.printStackTrace(); 默认是输出到System.err所关联的设备中
}
}

}

-----------------------------------------------------------------------------------------------------

import java.io.*;

public class TestSys
{
public static void main(String[] args) throws Exception
{
PrintStream ps = new PrintStream("d:/heihei.asd");
System.setOut(ps); // Out原本是输出到屏幕上的,但Out是PrintStream类型的,所以被Ps修改输出到了文件中。
System.out.println("哈哈");
}
}

-------------------------------------------------------------------------------------------------------

import java.io.*;

public class TestSetSystemOut
{
public static void main(String[] args)
{
PrintStream ps_out = null;

try
{
ps_out = new PrintStream(new FileOutputStream("d:/share/ww.txt"));
System.setOut(ps_out); //将System.out的值重新设置为ps_out,即System.out不在关联到显示器,而是关联到"d:/share/ww.txt"文件
System.out.println(12); //这实际上是把12输出到了System.out所关联的d:/share/ww.txt中
System.out.println(55.5); //同上
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
ps_out.close();
}
catch (Exception e)
{
e.printStackTrace();
}

}
}
}