Java 所有的文件操作类都在Java.io 包中。 注意五个类和一个接口。File OutputStream InputStream Writer Reader 一个接口是serializable

File

1
public File(String pathname)// file 类构造方法

要使用一个File类,需要传递一个文件路径

1

创建一个新文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.File;
import java.io.IOException;
public class FileDemo1
{
public static void main(String[] args)
{
File f = new File("D:\\test.txt");
try
{
f.createNewFile();
//if(f.exists()) judge exist
//f.delete() 删除文件
}
catch(IOException e)
{
e.printStackTrace();
}
}
}// windows 使用\ 表示目录
// linux 使用/ 表示目录

创建文件夹

1
2
File f = new File("/home/brett/java/io");
f.mkdir() && f.mkdirs()

RandomAccessFile 类

要对文件内容进行操作,使用randomAccessFile类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RandomAccessFile implements DataOutput, DataInput, Closeable 
{//下面是常用API.
//两个构造函数,指定操作文件.
public RandomAccessFile(String name, String mode)
public RandomAccessFile(File file, String mode)

public int read() throws IOException
public int read(byte b[], int off, int len) throws IOException
public void write(int b) throws IOException
public void write(byte b[]) throws IOException
public void seek(long pos) throws IOException //设置读指针的位置
public final byte readByte() throws IOException
public final int readInt() throws IOException
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class random_access_file {
public static void main(String[] args) throws Exception
{
//写操作
File f =new File("2.txt");//指定要操作的文件
RandomAccessFile rdf =new RandomAccessFile(f,"rw");// 读写方式打开文件,会自动创建新文件
String name ="wkn ";
int age = 23;
rdf.writeBytes(name);
rdf.write(23);
rdf.close();

//读操作
File f1 =new File("2.txt");
RandomAccessFile rdf2 =new RandomAccessFile(f1,"r");
byte[] b =new byte[8];
for(int i=0;i<b.length;i++)
{
b[i]=rdf2.readByte();
}
String name1 =new String(b);
System.out.printf(name1);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 String s = "wkn123王康宁";//String变量
byte b[] = s.getBytes();//String转换为byte[]
for(byte b1:b)
{
System.out.println(b1);
}
String t = new String(b);//byte[]转换为String
System.out.println(t);
// 所有字符都是以byte[]数组的形式传递的,默认utf8
// 英语和数字都是原来的ascll(utf8的英语数字和ascll一样)
// 其他字符可能是不同的编码,比如汉字就是三个数字一个编码。
//所以任何字符串都是可以转换为byte[]的形式的,
//byte[]也可以再转换为字符串。
// 一切“字符”都必定用数字+编码表表示
//当用UTF-8时表示一个字符是可变的,有可能是用一个字节表示一个字符,也可能是两个,三个.当然最多不能超过3个字节了.反正是根据字符对应的数字大小来确定.

可以参考http://www.cnblogs.com/fuzhaoyang56/archive/2013/05/24/3096471.html


字节流于字符流基本操作

在程序中所有的数据都是以流的方式进行传输或者保存的,程序需要数据时要使用输入流读取数据,而当程序需要将一些数据保存起来时,就要使用输出流。

1

io 包中流的操作主要有字节流,字符流两大类,两类都有输入和输出操作,在字节流中输出数据主要使用OutputStream 类完成,输入使用的是InputStream 类。在字符流中输出主要使用Writer类完成,输入主要使用Reader类完成。

操作流程如下

  • 使用file类打开一个文件
  • 通过字节流或者字符流的子类指定输出的位置
  • 进行读写操作
  • 关闭输入输出
    流在实例化的时候都需要传进去一个文件对象,表示流到哪或者从哪里流。

    字节流(主要操作byte[]类型数据 InputStream OutputStream)

OutputStream 是整个IO包中字节输出流的最大父类,定义如下

1
2
public abstruct class OutputStream extends Object implements Closeable, Flushable// 抽象类
里面主要定义了一个抽象方法,write().

InputStream 是整个IO包中字节输入流的最大父类,定义如下

1
2
public abstruct class InputStream extends Object implements Closeable, Flushable// 抽象类
里面主要定义了一个抽象方法,read().

字符流

在程序中一个字符相当于两个字节,Java提供了Reader 和Writer 两个专门操作字符流的类。

Writer 与outputStream 的操作流程并没有什么太大的去别,唯一的好处是,可以直接输出字符串,而不用将字符串变为byte[]数组之后再输出。Reader和Inputstream 也是类似。

reader inputstream 都是从文件(或其他)取数据 writer outputstream 往文件(或其他)写入数据

字节流在操作时本身不会用到缓冲区,是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再进行操作文件。所以字节流操作时不关闭也会有输入输出,字符流就不行,如果不关闭的话,就都在缓冲区里

转换流 OutputStreamWriter 和InputStream Reader

这两个流都是转换流。

outputStreamWriter 是writer的子类,将一个字符流的输出对象变为字节流输出对象。

inputStreamReader 是reader的子类,将一个字节流的输入对象变为字符流的输入对象。

System类对IO的支持

System类定义了三个常量,

1
2
3
public static final PrintStream out// 对应系统标准输出,一般是显示器
public static final PrintStream err//错误信息输出
public static final InputStream in // 对应标准输入,一般是键盘

System.out

System.out 是printStream的对象,在printStream 中定义了一系列print()和println()方法,printStream 又是OutputStream的子类.

1
2
OutputStream out = System.out;
out.write("Helo".getBytes());

System.err

System.err 表示的是错误信息输出,如果程序出现错误,可以直接使用System.err 进行输出.

1
2
3
4
5
6
7
try
{
System.out.print("hhh")
}catch (Exception e)
{
System.err.println(e);
}

System.in

System.in 实际上是一个键盘的输入流,其本身是InputStream类型的对象,那么此时就可以利用System.in 完成从键盘读取数据的功能.

1
2
3
4
5
InputStream input =System.in;
byte[] b = new byte[1024];
int len = input.read(b);
System.out.println(new String(b,0,len));
//此方法不常用,因为要提前申请,更好的方法是将全部输入暂存到内存的一块地方,然后一次性从内存中读取数据

BufferedReader类

BufferedReader 类用于从缓冲区读取内容,所有的输入字节数据都将放在缓冲区中.详见github IO

Scanner 类

JDK1.5后提供了专门的输入数据类,不只可以完成输入数据操作,也可以方便的对输入数据进行验证.

Scanner 可以接收任意的输入流.

对象序列化

对象序列化是把一个对象变为二进制的数据流的一种方法,通过序列化可以方便的实现对象的传输或者存储。如果一个类想被序列化,则对象所在的类必须实现 Java.io.serializable 接口, 此接口没有定义任何的方法,所以此接口是一个标识接口,表示一个类具备了被序列化的能力。

并发编程网上的IO总结

Java IO (ifeve.com)

Java.io包主要包括文件,网络数据流,内存缓冲等的输入输出。(从CPU的角度来看输入输出)。

Java IO 概述

Java IO 主要关注的是从原始数据源的读取以及输出原始数据到目标媒介。原始的数据源包括了 文件,管道,网络连接,内存缓存。

Java IO中,流从概念上说是一个连续的数据流,既可以从流总读取数据,也可以从流中写数据。 Java中流可以是字节流,也可以是字符流。

一个程序需要InputStream 或者reader 从数据源读取数据,需要outputstream 或者writer 将数据写到目标媒介中。

Java IO 文件

通过IO 读文件

根据该文件是二进制文件还是文本文件来选择使用FileInputStream或者FileReader。这两个类允许你从文件开始到文件末尾一次读取一个字节或者字符。或者将读取到的字节或字符写到数组里。

通过IO 写文件

如果需要在不同端之间写文件,根据你要写入的数据是二进制型数据还是字符型数据选用FileOutputStream或者FileWriter。

随机存取文件

通过RandomAccessFile对文件进行随机存取。

Java IO 管道

Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力。所以管道也可以作为数据源以及目标媒介。

Java IO 网络

当两个进程之间建立了网络连接之后,他们通信的方式如同操作文件一样:利用InputStream读取数据,利用OutputStream写入数据。换句话来说,Java网络API用来在不同进程之间建立网络连接,而Java IO则用来在建立了连接之后的进程之间交换数据。

Java IO 字节和字符数组

从inputstream 或者reader中读取数组。
1
2
3
4
5
6
7
byte[] bytes  = new byte[1024];
把数据写入数组
InputStream InputStream = new InputStream(bytes);
// 读取一个字节
int data = InputStream.read();
//读取下一个字节
int data2 = InputStream.read();

同样的方式也可以读取字符数组,把字符数组封装在charArrayReader上就行。

从Outputstream 或者writer写数组

同样,也可以把数据写到ByteArrayOutputStream或者CharArrayWriter中。你只需要创建ByteArrayOutputStream或者CharArrayWriter,把数据写入。

当所有的数据都写进去了以后,只要调用toByteArray()或者toCharArray,所有写入的数据就会以数组的形式返回。

1
2
3
OutputStram output =  new ByteArrayOutputStream();
output.write("this is a text".toBytes('UTF-8'));
byte[] bytes = output.toByteArray();

Java IO: 流

流和数组不一样,不能通过索引读写数据,在流中,也不能像数组那样前后移动读取数据,除非使用randomaccessFile 处理文件。流仅仅是一个连续的数据流。

InputStream

InputStream 是所有JavaIO 输入流的基类,通常使用输入流中的read()方法读取数据,read方法返回一个整数,代表了读取到的字节的内容,当到达流的末尾没有更多数据可以读时,返回-1

1
2
3
4
5
InputStream input = new FileInputStream("c:\\data\\input-file.txt");
int data = input.read();
while(data != -1){
data = input.read();
}
outputstream

OutputStream是Java IO中所有输出流的基类.

1
2
3
OutputStream output = new FileOutputStream("c:\\data\\output-file.txt");
output.write("Hello World".getBytes());
output.close();
组合流

可以将流整合起来以便实现更高级的输入和输出操作。比如,一次读取一个字节是很慢的,所以可以从磁盘中一次读取一大块数据,然后从读到的数据块中获取字节。为了实现缓冲,可以把InputStream包装到BufferedInputStream中。

1
InputStream input = new BufferedInputStream(new FileInputStream("c:\\data\\input-file.txt"));
reader

Reader类是Java IO中所有Reader的基类。子类包括BufferedReader,PushbackReader,InputStreamReader,StringReader和其他Reader.这并不意味着Reade只会从数据源中一次读取2个字节,Reader会根据文本的编码,一次读取一个或者多个字节。

并发IO

在同一时刻不能有多个线程同时InputStream 或者 Reader 中读取数据,也不能同时往outputStream 或者writer里写数据,你没有办法保证每个线程读取多少数据,以及多个线程写数据时的顺序。

异常处理

流与reader writer 使用结束的时候,需要正确的关闭它们,通常调用close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
InputStream input = null;

try{
input = new FileInputStream("c:\\data\\input-text.txt");
int data = input.read();
while(data != -1) {
//do something with data...
doSomethingWithData(data);
data = input.read();
}
}catch(IOException e){
//do something with e... log, perhaps rethrow etc.
} finally {
try{
if(input != null)
input.close();
} catch(IOException e){
//do something, or ignore.
}
}

Fileinputstream

1
2
3
4
5
6
7
8
9
10
InputStream input = new FileInputStream("c:\\data\\input-text.txt");
int data = input.read();while(data != -1) {
//do something with data...
doSomethingWithData(data);
data = input.read();
}
input.close();
//中一个FileInputStream构造函数取一个File对象替代String对象作为参数。这里是一个使用该构造函数的例子:
File file = new File("c:\\data\\input-text.txt");
InputStream input = new FileInputStream(file);

FileInputStream的read()方法返回读取到的包含一个字节内容的int变量(译者注:0~255)。如果read()方法返回-1,意味着程序已经读到了流的末尾,此时流内已经没有多余的数据可供读取了,你可以关闭流。-1是一个int类型,不是byte类型,这是不一样的。

FileOutputstream

1
2
3
4
5
6
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt");
while(moreData) {
int data = getMoreData();
output.write(data);
}
output.close();

当你创建了一个指向已存在文件的FileOutputStream,你可以选择覆盖整个文件,或者在文件末尾追加内容。通过使用不同的构造函数可以实现不同的目的。

1
2
3
4
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt");
另外一个构造函数取2个参数:文件名和一个布尔值,布尔值表明你是否需要覆盖文件。这是构造函数的例子:
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt", true); //appends to file
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt", false); //overwrites file

flush()

当你往FileOutputStream里写数据的时候,这些数据有可能会缓存在内存中。在之后的某个时间,比如,每次都只有X份数据可写,或者FileOutputStream关闭的时候,才会真正地写入磁盘。当FileOutputStream没被关闭,而你又想确保写入到FileOutputStream中的数据写入到磁盘中,可以调用flush()方法,该方法可以保证所有写入到FileOutputStream的数据全部写入到磁盘中。

File

1
2
3
File file = new File('/home/brett/2.txt');
上句相当于获得了一个门把手,但是不知道门是否存在,若不存在的话就可以使用
f.createNewFile()创建文件。