学习Java IO,不得不提到的就是JavaIO流。
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。
结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
从输入字节流的继承图可以看出:
InputStream 是所有的输入字节流的父类,它是一个抽象类。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
ObjectInputStream 和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。而DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in)。如下图示:
【案例 】读取文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 字节流
* 读文件内容
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
InputStream in=
new
FileInputStream(f);
byte
[] b=
new
byte
[
1024
];
in.read(b);
in.close();
System.out.println(
new
String(b));
}
}
|
注意:该示例中由于b字节数组长度为1024,如果文件较小,则会有大量填充空格。我们可以利用in.read(b);的返回值来设计程序,如下案例:
【案例】读取文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 字节流
* 读文件内容
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
InputStream in=
new
FileInputStream(f);
byte
[] b=
new
byte
[
1024
];
int
len=in.read(b);
in.close();
System.out.println(
"读入长度为:"
+len);
System.out.println(
new
String(b,
0
,len));
}
}
|
注意:观察上面的例子可以看出,我们预先申请了一个指定大小的空间,但是有时候这个空间可能太小,有时候可能太大,我们需要准确的大小,这样节省空间,那么我们可以这样做:
【案例】读取文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 字节流
* 读文件内容,节省空间
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
InputStream in=
new
FileInputStream(f);
byte
[] b=
new
byte
[(
int
)f.length()];
in.read(b);
System.out.println(
"文件长度为:"
+f.length());
in.close();
System.out.println(
new
String(b));
}
}
|
【案例】逐字节读
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 字节流
* 读文件内容,节省空间
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
InputStream in=
new
FileInputStream(f);
byte
[] b=
new
byte
[(
int
)f.length()];
for
(
int
i =
0
; i < b.length; i++) {
b[i]=(
byte
)in.read();
}
in.close();
System.out.println(
new
String(b));
}
}
|
注意:上面的几个例子都是在知道文件的内容多大,然后才展开的,有时候我们不知道文件有多大,这种情况下,我们需要判断是否独到文件的末尾。
【案例】字节流读取文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 字节流
*读文件
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
InputStream in=
new
FileInputStream(f);
byte
[] b=
new
byte
[
1024
];
int
count =
0
;
int
temp=
0
;
while
((temp=in.read())!=(-
1
)){
b[count++]=(
byte
)temp;
}
in.close();
System.out.println(
new
String(b));
}
}
|
注意:当读到文件末尾的时候会返回-1.正常情况下是不会返回-1的。
【案例】DataInputStream类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import
java.io.DataInputStream;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.IOException;
public
class
DataOutputStreamDemo{
public
static
void
main(String[] args)
throws
IOException{
File file =
new
File(
"d:"
+ File.separator +
"hello.txt"
);
DataInputStream input =
new
DataInputStream(
new
FileInputStream(file));
char
[] ch =
new
char
[
10
];
int
count =
0
;
char
temp;
while
((temp = input.readChar()) !=
'C'
){
ch[count++] = temp;
}
System.out.println(ch);
}
}
|
【案例】PushBackInputStream回退流操作
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
|
import
java.io.ByteArrayInputStream;
import
java.io.IOException;
import
java.io.PushbackInputStream;
/**
* 回退流操作
* */
public
class
PushBackInputStreamDemo{
public
static
void
main(String[] args) throwsIOException{
String str =
"hello,rollenholt"
;
PushbackInputStream push =
null
;
ByteArrayInputStream bat =
null
;
bat =
new
ByteArrayInputStream(str.getBytes());
push =
new
PushbackInputStream(bat);
int
temp =
0
;
while
((temp = push.read()) != -
1
){
if
(temp ==
','
){
push.unread(temp);
temp = push.read();
System.out.print(
"(回退"
+(
char
) temp +
") "
);
}
else
{
System.out.print((
char
) temp);
}
}
}
}
|
IO 中输出字节流的继承图可见上图,可以看出:
OutputStream 是所有的输出字节流的父类,它是一个抽象类。
ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
ObjectOutputStream 和所有FilterOutputStream的子类都是装饰流。具体例子跟InputStream是对应的。
【案例】向文件中写入字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 字节流
* 向文件中写入字符串
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
OutputStream out =
new
FileOutputStream(f);
String str=
"Hello World"
;
byte
[] b=str.getBytes();
out.write(b);
out.close();
}
}
|
你也可以一个字节一个字节的写入文件:
【案例】逐字节写入文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 字节流
* 向文件中一个字节一个字节的写入字符串
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
OutputStream out =
new
FileOutputStream(f);
String str=
"Hello World!!"
;
byte
[] b=str.getBytes();
for
(
int
i =
0
; i < b.length; i++) {
out.write(b[i]);
}
out.close();
}
}
|
【案例】向文件中追加新内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/**
* 字节流
* 向文件中追加新内容:
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String fileName=
"D:"
+File.separator+
"hello.txt"
;
File f=
new
File(fileName);
OutputStream out =
new
FileOutputStream(f,
true
);
//true表示追加模式,否则为覆盖
String str=
"Rollen"
;
//String str="\r\nRollen"; 可以换行
byte
[] b=str.getBytes();
for
(
int
i =
0
; i < b.length; i++) {
out.write(b[i]);
}
out.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
|
/**
* 文件的复制
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
if
(args.length!=
2
){
System.out.println(
"命令行参数输入有误,请检查"
);
System.exit(
1
);
}
File file1=
new
File(args[
0
]);
File file2=
new
File(args[
1
]);
if
(!file1.exists()){
System.out.println(
"被复制的文件不存在"
);
System.exit(
1
);
}
InputStream input=
new
FileInputStream(file1);
OutputStream output=
new
FileOutputStream(file2);
if
((input!=
null
)&&(output!=
null
)){
int
temp=
0
;
while
((temp=input.read())!=(-
1
)){
output.write(temp);
}
}
input.close();
output.close();
}
}
|
【案例】使用内存操作流将一个大写字母转化为小写字母
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 使用内存操作流将一个大写字母转化为小写字母
* */
import
java.io.*;
class
hello{
public
static
void
main(String[] args)
throws
IOException {
String str=
"ROLLENHOLT"
;
ByteArrayInputStream input=
new
ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream output=
new
ByteArrayOutputStream();
int
temp=
0
;
while
((temp=input.read())!=-
1
){
char
ch=(
char
)temp;
output.write(Character.toLowerCase(ch));
}
String outStr=output.toString();
input.close();
output.close();
System.out.println(outStr);
}
}
|
【案例】验证管道流:进程间通信
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
|
/**
* 验证管道流
* */
import
java.io.*;
/**
* 消息发送类
* */
class
Send
implements
Runnable{
private
PipedOutputStream out=
null
;
public
Send() {
out=
new
PipedOutputStream();
}
public
PipedOutputStream getOut(){
return
this
.out;
}
public
void
run(){
String message=
"hello , Rollen"
;
try
{
out.write(message.getBytes());
}
catch
(Exception e) {
e.printStackTrace();
}
try
{
out.close();
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
/**
* 接受消息类
* */
class
Recive
implements
Runnable{
private
PipedInputStream input=
null
;
public
Recive(){
this
.input=
new
PipedInputStream();
}
public
PipedInputStream getInput(){
return
this
.input;
}
public
void
run(){
byte
[] b=
new
byte
[
1000
];
int
len=
0
;
try
{
len=
this
.input.read(b);
}
catch
(Exception e) {
e.printStackTrace();
}
try
{
input.close();
}
catch
(Exception e) {
e.printStackTrace();
}
System.out.println(
"接受的内容为 "
+(
new
String(b,
0
,len)));
}
}
/**
* 测试类
* */
class
hello{
public
static
void
main(String[] args)
throws
IOException {
Send send=
new
Send();
Recive recive=
new
Recive();
try
{
//管道连接
send.getOut().connect(recive.getInput());
}
catch
(Exception e) {
|