Java IO
1,概述
Java IO是Java用来读写数据(输入和输出)的API。这里主要介绍以下几点内容:
Java流式输入/输出
Java流类的分类
输入/输出流类
常见的节点流和处理流
文件流
缓冲流
数据流
转换流
Print流
Object流
2,Java流式输入和输出
在Java程序中,对于数据的输入输出操作以"流"(Stream)方式进行;J2SDK提供了各种各样的"流"类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。各类用途汇总如下:
- 文件访问
- 网络访问
- 内存缓存访问
- 线程内部通信(管道)
- 缓冲
- 过滤
- 解析
- 读写文本 (Readers / Writers)
- 读写基本类型数据 (long, int etc.)
- 读写对象
3,Java流的分类
java.io包中定义了多个流类型(类或抽象类)来实现输入/输出功能。可以从不同的角度对其进行分类:
- 按数据流的方向不同可以分为输入流和输出流;
- 按处理数据单位不同可以分为字节流和字符流(一个字节1 byte=8 bits,一个字符Unicode=2字节);
- 按照功能不同可以分为节点流和处理流;
输入和输出:四个抽象类(凡是Stream结尾的否是字节流)
字节流 | 字符流 | |
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
节点流和处理流:
节点流为可以从一个特定的数据源(节点)读写数据(比如:文件,内存)
处理流是“连接”在已经存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能:
4,InputStream & OutputStream,Reader & Writer
4.1,InputStream
继承自InputStream的流都是用于向程序中输入数据,且数据的单位为字节(byte,8bits),下图中深色为节点流,浅色为处理流。
InputStream的基本方法:
//读取一个字节并以整数的形式返回(0~255)
//如果返回-1表示已到输入流的末尾
int read() throws IOException
//读取一系列字节并存储到一个数组buffer
//返回实际读取的字节数,如果读取前已到输入流的末尾返回-1
int read(byte[] buffer) throws IOException
//读取length个字节
//并存储到一个字节数组buffer,从length位置开始
//返回实际读取的字节数,如果读取前已到输入流的末尾返回-1
int read(byte[] buffer, int offset, int length) throws IOException
//关闭流释放内存资源
void close() throws IOException
//跳过n个字节不读,返回实际跳过的字节数
long skip(long n) throws IOException
4.2,OutputStream
继承自OutputStream的流是用于从程序中输出数据,切数据的单位是字节(byte,8bits),下图中深色为节点流,浅色为处理流。
OutputStream的基本方法:
//向输出流中写入一个字节数据,该字节数据位参数b的低8位
void write(int b) throws IOException
//将一个字节类型的数组中的数据写入输出流
void writer(byte[] b) throws IOException
//将一个字节类型的数组中的数据从指定位置(off)开始len个字节写入到输出流
void write(byte[] b, int off, int len) throws IOException
//关闭流释放内存资源
void close() throws IOException
//将输出流中缓冲的数据全部写出到目的地
void flush() throws IOException
4.3,Reader
继承自Reader的流都是用于向程序中输入数据,且数据的单位是字符(16bits,例如一个中文是两个字节表示);下图中深色为节点流,浅色为处理流:
Reader的基本方法
//读取一个字符并以整数的形式返回(0~255)
//如果返回-1表示已到输入流的末尾
int read() throws IOException
//读取一系列字符并存储到一个数组buffer
//返回实际读取的字符数,如果读取前已到输入流的末尾返回-1表示已到输入流的末尾
int read(char[] cbuf) throws IOException
//读取length个字符
//并存储到一个数组buffer,从length位置开始
//返回实际读取的字符数,如果读取前已到输入流的末尾返回-1表示已到输入流的末尾
int read(char[] cbuf, int offset, int length) throws IOException
//关闭流释放内存资源
void close() throws IOException
//跳过n个字符不读,返回实际跳过的字节数
long skip(long n) throws IOException
4.4,Writer
继承自Writer的流都是用于程序中输出数据,且数据的单位为字符(16bits);下图中深色为节点流,浅色为处理流:
Writer基本方法:
//向输出流中写入一个字符数据,该字符数据为参数c的低16位
void write(int c) throws IOException
//将一个字符类型的数组中的数据写入输出流
void writer(char[] cbuf) throws IOException
//将一个字符类型的数组中的数据从指定位置(offset)开始len个字节写入到输出流
void write(char[] cbuf, int offset, int len) throws IOException
//将一个字符串中的字符写入到输出流
void write(String string) throws IOException
//将一个字符串从offset开始的length个字符写入到输出流
void write(String string, int offset, int length) throws IOException
//关闭流释放内存资源
void close() throws IOException
//将输出流中缓冲的数据全部写出到目的地
void flush() throws IOException
5,常用的节点流和处理流
5.1,节点流类型
类型 | 字符流 | 字节流 |
File(文件) |
FileReader FileWriter |
FileInputStream FileOutputStream |
Memory Array |
CharArrayReader CharArrayWriter |
ByteArrayInputStream ByteArrayOutputStream |
Memory String |
StringReader StringWriter |
--- |
Pipe(管道,线程) |
PipedReader PipedWriter |
PipedInputStream PipedOutputStream |
5.1.1,File(访问文件)
FileInputStream和FileOutputStream分别继承自OutputStream和OutputStream,用于向文件中输入和输出字节。
FileInputStream和FileOutputStream的构造方法:
FileInputStream:
FileInputStream(File file)
Creates a FileInputStream by opening a connection to an actual file, the file named by the File object file in the file system.
FileInputStream(FileDescriptor fdObj)
Creates a FileInputStream by using the file descriptor fdObj, which represents an existing connection to an actual file in the file system.
FileInputStream(String name)
Creates a FileInputStream by opening a connection to an actual file, the file named by the path name name in the file system.
OutputStream:
FileOutputStream(File file)
Creates a file output stream to write to the file represented by the specified File object.
FileOutputStream(File file, boolean append)
Creates a file output stream to write to the file represented by the specified File object.
FileOutputStream(FileDescriptor fdObj)
Creates a file output stream to write to the specified file descriptor, which represents an existing connection to an actual file in the file system.
FileOutputStream(String name)
Creates a file output stream to write to the file with the specified name.
FileOutputStream(String name, boolean append)
Creates a file output stream to write to the file with the specified name.
FileInputStream和FileOutputStream类支持其父类InputStream和OutputStream所提供的数据读写方法。
注意:
在实例化FileInputStream和FileOutputStream时要用ty-catch语句加以处理,因为可能抛出FileNotFoundException。
在读写数据时也要用try-catch语句加以处理,因为可能抛出IOException。
例子:
1,FileInputStream & FileOutputStream
FileInputStream:
public static void main(String[] args) {
int b = 0;
FileInputStream fis = null;
try {
fis = new FileInputStream("d:\\share\\java\\io\\TestFileInputStream.java");
} catch (FileNotFoundException e) {
System.out.println("找不到指定文件");
System.exit(-1);
}
try {
long num = 0;
while((b = fis.read()) != -1) {
System.out.print((char)b);
num++;
}
fis.close();
System.out.println("共读取了" + num + "个字节");
} catch (IOException e) {
System.out.println("文件读取错误");
System.exit(-1);
}
}
结果:对于中文乱码,因为是一个字节一个字节的读取,所以只读取了半个中文
控制台输出:
import java.io.*;
public class TestFileInputStream {
public static void main(String[] args) {
int b = 0;
FileInputStream in = null;
try {
in = new FileInputStream("d:\\share\\java\\io\\TestFileInputStream.java");
} catch (FileNotFoundException e) {
System.out.println("ÕÒ²»µ½Ö¸¶¨Îļþ");
System.exit(-1);
}
try {
long num = 0;
while((b=in.read())!=-1){
System.out.print((char)b);
num++;
}
in.close();
System.out.println();
System.out.println("¹²¶ÁÈ¡ÁË "+num+" ¸ö×Ö½Ú");
} catch (IOException e1) {
System.out.println("Îļþ¶ÁÈ¡´íÎó"); System.exit(-1);
}
}
}共读取了700个字节
FileOutputStream:
public static void main(String[] args) {
int b = 0;
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("d:/share/java/HelloWorld.java");
fos = new FileOutputStream("d:/share/java/io/HW.java");//没有回自动新建一个文件
while ((b = fis.read()) != -1) {
fos.write(b);
}
fis.close();
fos.close();
} catch (FileNotFoundException e) {
System.out.println("找不到指定的文件");
System.exit(-1);
} catch (IOException e) {
System.out.println("文件复制错误");
System.exit(-1);
}
System.out.println("文件已复制");
}
输出:可以在d:/share/java/io中看到复制的文件HW.java
2,FileReader & FileWriter
FileReader:
public static void main(String[] args) {
int c = 0;
FileReader fr = null;
try {
fr = new FileReader("d:\\share\\java\\io\\TestFileReader.java");
while((c = fr.read()) != -1) {
System.out.print((char)c);
}
fr.close();
} catch (FileNotFoundException e) {
System.out.println("找不到指定文件");
} catch (IOException e) {
System.out.println("读取文件出错");
}
}
FileWriter:
例一:
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter(new File("d:\\unicode.dat"));
for(int i = 0; i <= 50000; i++) {//char最大为65535
fw.write(i);
}
fw.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件写入错误");
System.exit(-1);
}
}
结果:D盘中的unicode.dat文件中的内容。
例二:
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("d:/java/io/TestFileWriter2.java");
FileWriter fw = new FileWriter("d:/java/io/TestFileWriter2.bak");
int b;
while((b = fr.read()) != -1) {
fw.write(b);
}
fr.close();
fw.close();
}
5.2,处理流
处理流需要套接在节点流和其他处理流之上使用
处理类型 | 字符流 | 字节流 |
Buffering |
BufferReader BufferWriter |
BufferedInputStream BufferedOutputStream |
Converting between bytes and character |
InputStreamReader OutputStreamWriter |
|
Object Serialization | --- |
ObjectInputStream ObjectOutputstream |
Data Conversion | --- |
DataInputStream DataOutputStream |
Counting | LineNumberReader | LineNumberInputStream |
Peeking ahead | PushbackReader |
PushbackInputStream |
Printing | PrintWriter | PrintStream |
5.2.1,缓冲流
缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。
J2SDK提供了四种缓冲流,其常用的构造方法:
BufferedReader
BufferedReader(Reader in)
Creates a buffering character-input stream that uses a default-sized input buffer.
BufferedReader(Reader in, int sz)
Creates a buffering character-input stream that uses an input buffer of the specified size.
BufferedWriter
BufferedWriter(Writer out)
Creates a buffered character-output stream that uses a default-sized output buffer.
BufferedWriter(Writer out, int sz)
Creates a new buffered character-output stream that uses an output buffer of the given size.
BufferedInputStream
BufferedInputStream(InputStream in)
Creates a BufferedInputStream and saves its argument, the input stream in, for later use.
BufferedInputStream(InputStream in, int size)
Creates a BufferedInputStream with the specified buffer size, and saves its argument, the input stream in, for later use.
BufferedOutputStream
BufferedOutputStream(OutputStream out)
Creates a new buffered output stream to write data to the specified underlying output stream.
BufferedOutputStream(OutputStream out, int size)
Creates a new buffered output stream to write data to the specified underlying output stream with the specified buffer size.
缓冲输入流支持其父类的mark和reset方法
BufferedReader提供了readLine方法用于读取一行字符串(以\r或\n分隔)
BufferedWriter提供了newLine方法用于写入一个行分隔符
对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush方法将会使内存中的数据立刻写出。
例一:
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("d:\\share\\java\\HelloWorld.java");
BufferedInputStream bis = new BufferedInputStream(fis);
int c = 0;
System.out.println(bis.read());
System.out.println(bis.read());
bis.mark(100);
for(int i = 0; i <= 10 && (c=bis.read()) != -1; i++) {
System.out.print((char)c + " ");
}
System.out.println();
bis.reset();
for(int i = 0; i <= 10 && (c=bis.read()) != -1; i++) {
System.out.print((char)c + " ");
}
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
输出:
47
42
a l ; s k j d f ;
a l ; s k j d f ;
例二:
public static void main(String[] args) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\dat2.txt"));
BufferedReader br = new BufferedReader(new FileReader("d:\\dat2.txt"));
String s = null;
for(int i = 1; i<=100; i++) {
s = String.valueOf(Math.random());
bw.write(s);
bw.newLine();
}
bw.flush();
while((s = br.readLine()) != null) {//读一行
System.out.println(s);
}
bw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
输出:
dat2.txt文件:
控制台输出:
5.2.2,转换流
InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换。
InputStreamReader需要和InputStream套接(把InputStream转换成InputStreamReader)
OutputStreamWriter需要和OutputStream套接(把OutputStreamWriter转换成OutputStream)
转换流在构造时可以指定其编码集合,例如:
InputStream is = new InputStreamReader(System.in, "IOS8859_1");
例一:
public static void main(String[] args) {
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\bak\\char.txt"));
osw.write("miscalkjsdlasjdlajslkdalksd");
System.out.println(osw.getEncoding());
osw.close();
osw = new OutputStreamWriter(new FileOutputStream("d:\\bak\\char.txt", true), "ISO8859_1");//true,追加
osw.write("sadasdasdasdasd");
System.out.println(osw.getEncoding());
osw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
结果:
UTF8//系统默认的编码
ISO8859_1
例二:
public static void main(String[] args) {
try {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = null;
s = br.readLine();
while(s != null) {
if("exit".equalsIgnoreCase(s))
break;
System.out.println(s.toUpperCase());
s = br.readLine();
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
输出:
add111
ADD111
exit
5.2.3,数据流
DataInputStream 和DataOutputStream分别继承自InputStream 和 OutputStream,它属于处理流,需要分别套接在InputStream 和 OutputStream类型的节点流上。
DataInputStream 和DataOutputStream提供了可以存取与机器无关的Java原始类型数据(如:int,double等)的方法。
DataInputStream 和DataOutputStream的构造方法:
DataInputStream(InputStream in)
Creates a DataInputStream that uses the specified underlying InputStream.
DataOutputStream(OutputStream out)
Creates a new data output stream to write data to the specified underlying output stream.
ByteArrayInputStream 和 ByteArrayOutputStream
例子:
public static void main(String[] args) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//在内存中分配了一个字节数组
DataOutputStream dos = new DataOutputStream(baos);
dos.writeDouble(Math.random());
dos.writeBoolean(true);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
System.out.println(bais.available());
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
dos.close();
dis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
结果:
9
0.5620896958440097
true
5.2.4,Print流
Print流(只有输出流没有输入流)
PrintWriter和PrintStream都属于输出流,分别针对于字符和字节
PrintWriter和PrintStream提供了重载的print方法
Println方法用于多种数据类型的输出
PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息
PrintWriter和PrintStream有自动flush方法
构造方法:
PrintWriter(File file)
Creates a new PrintWriter, without automatic line flushing, with the specified file.
PrintWriter(File file, String csn)
Creates a new PrintWriter, without automatic line flushing, with the specified file and charset.
PrintWriter(OutputStream out)
Creates a new PrintWriter, without automatic line flushing, from an existing OutputStream.
PrintWriter(OutputStream out, boolean autoFlush)
Creates a new PrintWriter from an existing OutputStream.
PrintWriter(String fileName)
Creates a new PrintWriter, without automatic line flushing, with the specified file name.
PrintWriter(String fileName, String csn)
Creates a new PrintWriter, without automatic line flushing, with the specified file name and charset.
PrintWriter(Writer out)
Creates a new PrintWriter, without automatic line flushing.
PrintWriter(Writer out, boolean autoFlush)
Creates a new PrintWriter.
PrintStream(File file)
Creates a new print stream, without automatic line flushing, with the specified file.
PrintStream(File file, String csn)
Creates a new print stream, without automatic line flushing, with the specified file and charset.
PrintStream(OutputStream out)
Creates a new print stream.
PrintStream(OutputStream out, boolean autoFlush)
Creates a new print stream.
PrintStream(OutputStream out, boolean autoFlush, String encoding)
Creates a new print stream.
PrintStream(String fileName)
Creates a new print stream, without automatic line flushing, with the specified file name.
PrintStream(String fileName, String csn)
Creates a new print stream, without automatic line flushing, with the specified file name and charset.
例一:
public static void main(String[] args) {
try {
PrintStream ps = null;
FileOutputStream fos = new FileOutputStream("d:\\bak\\log.dat");
ps = new PrintStream(fos);
if(ps != null) {
System.setOut(ps);//把ps设置成System.out.println();不再输出在控制台了
}
int ln = 0;
for(char c = 0; c <= 60000; c++) {
System.out.print(c + "");
if( ln++ >= 100) {
System.out.println();
ln = 0;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
结果:d:\\bak\\log.dat,log.data文件
例二:
public static void main(String[] args) {
try {
PrintStream ps = System.out;
BufferedReader br = new BufferedReader(new FileReader("d:\\bak\\log.dat"));
String s = null;
while((s = br.readLine()) != null) {
ps.println(s);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
结果:
例三:
public static void main(String[] args) {
try {
String s = null;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
FileWriter fw = new FileWriter("d:\\bak\\logfile.log", true);//日志
PrintWriter pw = new PrintWriter(fw);
while ((s = br.readLine()) != null) {
if("exit".equalsIgnoreCase(s))
break;
System.out.println(s.toUpperCase());
pw.println("--------");
pw.println(s.toUpperCase());
pw.flush();
}
pw.println("=====" + new Date() + "======");
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
结果:
控制台:
12121212121
adasdasdasdasd
ADASDASDASDASD
exit
文件:d:\\bak\\logfile.log,logfile.log文件
5.2.5,Object流
直接将Object写入或写出
transient关键字
serializable接口
externalizable接口
例一:
public class Test {
public static void main(String[] args) {
try {
T t = new T();
t.k = 18;
FileOutputStream fos = new FileOutputStream("d:/bak/testobjectio.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(t);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("d:/bak/testobjectio.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
T t2 = (T) ois.readObject();
System.out.println(t2.i + "//" + t2.j + "//" + t2.d + "//" + t2.k);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class T implements Serializable {
int i = 10;
int j = 9;
double d = 2.3;
int k = 15;
}
结果:
10//9//2.3//18
例二:
用transient修饰变量k
class T implements Serializable {
int i = 10;
int j = 9;
double d = 2.3;
transient int k = 15;
}
结果:
10//9//2.3//0
transient修饰的变量k不会被写入进去,所以取出来的k为空,为默认值0