1.简介
io流
作用是:读写设备上的数据(硬盘文件、内存、键盘、网络)。
根据数据的走向,可分为:输入流、输出流。
根据处理的数据类型,可分为:字节流、字符流。
字节流和字符流
1.字节流可以处理所有类型的数据,如Mp3、图片、文字、视频等。在读取数据时候,读到一个字节就返回一个字节。在java中对应的类都是以"Stream”结尾。
2.字符流只能处理纯文本数据,如txt文本等。在读取数据时候,读到一个或者多个字节,先查找指定编码表,然后将查到的字符返回。在java中对应的类都是以“Reader”或“Writer”结尾。
2.字节流操作
使用字节流读写数据
从文件中读取数据例子:
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("text.txt");//文件路径
byte[] input = new byte[30];
fis.read(input);
String inputString = new String(input, "UTF-8");
System.out.println(inputString);
fis.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
写入数据例子:
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("textw.txt");
String outString = "写数据到文件, write 123456";
byte output[] = outString.getBytes("UTF-8");
fos.write(output);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
copy文件例子:
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("movie.mp4");
FileOutputStream fos = new FileOutputStream("movie_new.mp4");
byte input[] = new byte[50];
long before = System.currentTimeMillis();
int count = 0;
while (fis.read(input) != -1) {
fos.write(input);
count++;
}
fos.flush();
fis.close();//
fos.close();
System.out.println(System.currentTimeMillis() - before + "ms");
System.out.println("done");
System.out.println("读取了:" + count + "次");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
上面例子中文件大小:323 MB
输出结果:
80566ms
done
读取了:6785376次
使用带缓冲的字节流读写数据
使用带缓冲的字节流实现上述文件copy功能
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("movie.mp4");
BufferedInputStream bis = new BufferedInputStream(fis, 1000000);
FileOutputStream fos = new FileOutputStream("moive_new.mp4");
BufferedOutputStream bos = new BufferedOutputStream(fos, 1000000);
// 大型文件对应的数组可以大一些,小文件对应的数组小一些
byte input[] = new byte[100000];
int count = 0;
long before = System.currentTimeMillis();
while (bis.read(input) != -1) {
bos.write(input);
count++;
}
bos.flush();
bis.close();
fis.close();
bos.close();
fos.close();
System.out.println(System.currentTimeMillis() - before + "ms");
System.out.println("读取了:" + count + "次");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
上面例子中文件大小:323 MB
输出结果:
782ms
读取了:3393次
对比可以看出,用带缓冲字节流方式效率提高不少。有两个设置关系到读写效率,一个是缓冲就初始化大小、另外一个是字节数组初始化大小。需要根据实际文件大小进行设置。
2.字符流操作
使用字符流读写数据
public static void main(String[] args) {
try{
//File file = new File("java.txt");
//FileInputStream fis= new FileInputStream(file);
FileInputStream fis = new FileInputStream("java.txt");
FileOutputStream fos = new FileOutputStream("java_new.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
char input[] = new char[100];
int l = 0;
while ((l = isr.read(input)) != -1) {
//String inputString = new String(input,0,l);
osw.write(input,0,l);
}
isr.close();
fis.close();
osw.close();
fos.close();
System.out.println("done");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
使用带有缓冲的字符流读写数据
public static void main(String[] args) {
try {
//File file = new File("java.txt");
FileInputStream fis = new FileInputStream("java.txt");
FileOutputStream fos = new FileOutputStream("java_new_buff.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedReader br = new BufferedReader(isr);
//使用bw写入时,会丢失换行符,输出的结果不会换行
//BufferedWriter bw = new BufferedWriter(osw);
//打印包含换行符,true--表示自动flush,无需最后调用flush()
PrintWriter pw = new PrintWriter(osw,true);
String input;
while ((input = br.readLine()) != null) {
//bw.write(input);
pw.println(input);
}
br.close();
//bw.flush();bw.close();
pw.close();
isr.close();
fis.close();
osw.close();
fos.close();
System.out.println("done");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
注意:对于流的关闭,需要最后创建的流,先关闭。最先创建的流最后关闭。
3.FileReader与FileWriter
FileReader和FileWriter是专门操作纯文本的文件。
public static void main(String[] args) {
try {
FileReader fr = new FileReader("java.txt");
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter("java_new.txt");
BufferedWriter bw = new BufferedWriter(fw);
String line;
while ((line = br.readLine()) != null) {
bw.write(line+"\n");
}
bw.flush();
bw.close();
fw.close();
br.close();
fr.close();
System.out.println("done");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
4.RandomAccessFile随机文件读写
RandomAccessFile与普通的IO流相比,它最大的特别之处就是支持任意访问的方式,程序可以直接跳到任意地方来读写数据。如果我们只希望访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将会带来更简洁的代码以及更好的性能。
以下是使用RandomAccessFile写入文件的例子:
public class RandomAccessFileTest {
static File file = new File("test.txt");
/**
* @param args
*/
public static void main(String[] args) {
if (file.exists()) {
file.delete();
}
//不管线程顺序,写入文件内容一样,是按照指针位置写入的。
new WriteFile(file, 5).start();
new WriteFile(file, 3).start();
new WriteFile(file, 1).start();
new WriteFile(file, 4).start();
new WriteFile(file, 2).start();
}
}
class WriteFile extends Thread {
File file;
int block;
int L = 100;//每个block的字节数
/**
* 1 2 3 4 5(2)
* |------------|------------|------------|------------|------------|
* 0xL 1xL
*
* @param f
* @param b
*/
public WriteFile(File f,int b){
this.file = f;
this.block = b;
}
@Override
public void run() {
try {
RandomAccessFile raf = new RandomAccessFile(file, "rw");//rw-可读写模式
raf.seek((block-1)*L);//根据block值来确定写入指针位置。
raf.writeBytes("This is block"+block);
for (int i = 0; i < 20; i++) {
raf.writeBytes("-");
}
raf.writeBytes("\n");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
利用RandomAccessFile可以实现文件的多线程下载,即多线程下载一个文件时,将文件分成几块,每块用不同的线程进行下载。
以下是使用RandomAccessFile读取文件的例子:
public static void main(String[] args) {
try {
RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(300);//第四行记录
byte[] str = new byte[20];
raf.read(str);
String in = new String(str);
System.out.println(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
5使用Apache IO库操作IO与文件
使用Apache io 库需要引入commons-io-2.4.jar,这样就可以使用这个io库了。
下面是使用Apache io 库一个简单的例子:
public static void main(String[] args) {
File file = new File("text.txt");
File file2 = new File("text_new.txt");
try {
// String input = FileUtils.readFileToString(file, "UTF-8");
// System.out.println(input);
FileUtils.copyFile(file, file2);
} catch (IOException e) {
e.printStackTrace();
}
}