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(); } }