2.熟悉Java基本类库系列——Java IO 类库
Java中常用的IO操作基本上可以分为四大部分,分别是:File类操作、RandomAccessFile类操作、字节流操作、字符流操作。只要熟练掌握了本文中所列举的所有例子,基本上对于Java的IO流操作就可以说是掌握了。
下面将以JUnit测试用例的方式,用一个个例子的方式列出这四大部分中常用的操作例子。
一、File类操作
File类操作定义了最基本的、与操作系统的稳健系统相关的操作,可以对文件夹、文件进行一系列的操作。
1、常用的一些用法
//1.两个常量 @Test public void twoConstant(){ //输出: '/' ':' System.out.println(File.separator); System.out.println(File.pathSeparator); } //2.创建新文件 @Test public void createFile(){ File f = new File("hello"); try{ f.createNewFile(); System.out.println("创建了文件:" + f.getAbsolutePath()); }catch(Exception e){ e.printStackTrace(); } } //3.创建一个文件夹 @Test public void createFolder(){ try{ File file = new File("HelloFolder"); //当一个目录下既没有该名字对应的目录和文件时,才能建立该文件夹 if(!file.isDirectory() && !file.isFile()){ file.mkdir(); //file.mkdirs(); //如果上级目录不存在,那么一并创建上级目录 }else{ System.out.println("已存在该名称的文件或文件夹"); } }catch(Exception e){ e.printStackTrace(); } } //4.删除一个文件 @Test public void deleteFile(){ try{ File file = new File("hello"); if(file.exists()){ file.delete(); }else{ System.out.println("文件不存在"); } }catch(Exception e){ e.printStackTrace(); } } //5.删除一个文件夹(与删除文件一样) @Test public void deleteFolder(){ try{ File file = new File("HelloFolder"); if(file.exists()){ file.delete(); }else{ System.out.println("该文件夹不存在"); } }catch(Exception e){ e.printStackTrace(); } } //6.获取指定目录下所有文件的文件名(包括隐藏文件和文件夹) @Test public void getAllFileName(){ try{ File folder = new File("."); //当前目录 String[] fileStrs = folder.list(); for(String str : fileStrs){ System.out.print(str + " "); } }catch(Exception e){ e.printStackTrace(); } } //7.获取指定目录下所有文件的路径 @Test public void getAllFilePath(){ try{ File folder = new File("."); //当前目录 File[] files = folder.listFiles(); for(File file : files){ System.out.println(file.getCanonicalPath()); } }catch(Exception e){ e.printStackTrace(); } }
2、打印指定目录下的所有文件(递归调用)
package com.chanshuyi.io; /** * 列出指定目录的全部内容 * */ import java.io.*; class ListAllFile{ public static void main(String[] args) { File f = new File("."); print(f); } //递归打印 public static void print(File f){ if(f != null){ if(f.isDirectory()){ File[] fileArray = f.listFiles(); if(fileArray != null){ for(int i = 0; i < fileArray.length; i++){ print(fileArray[i]); } } }else{ System.out.println(f); } } } }
二、RandomAccessFile类操作
RandomAccessFile类可以对文件进行随机访问,比如可以指定读写指针到某一个字节处,也可以读写指针指定跳过指定字节数。简单地说,RandomAccessFile类提供了许多方法,使得我们可以对文件进行更加细致的读写操作。
//8.随机读写文件类 @Test public void operateRandom(){ try{ //1.跳过两个字节读取文件内容 //文件内容是:Hello, this is demo File. RandomAccessFile randomRW = new RandomAccessFile(new File("demo.txt"), "rw"); randomRW.skipBytes(2); //跳过两个字节,即跳过了'he'两个英文字符(一个英文字符占用1个字节) byte b[] = new byte[100]; int length = randomRW.read(b); System.out.println("总共读取了" + length + "个字节,读取的内容是:" + new String(b)); //总共读取了23个字节,读取的内容是:llo, this is demo File. //2.将读写指针跳回文件头重新读取 randomRW.seek(0); length = randomRW.read(b); System.out.println("总共读取了" + length + "个字节,读取的内容是:" + new String(b)); //总共读取了25个字节,读取的内容是:Hello, this is demo File. //3.获取读写指针所在地址 long pointer = randomRW.getFilePointer(); System.out.println("文件指针地址:" + pointer); //文件指针地址:25 randomRW.seek(2); pointer = randomRW.getFilePointer(); System.out.println("文件指针地址:" + pointer); //文件指针地址:2 randomRW.seek(77); pointer = randomRW.getFilePointer(); System.out.println("文件指针地址:" + pointer); //文件指针地址:77 randomRW.close(); }catch(Exception e){ e.printStackTrace(); }
三、字节流读写
FileInputStream / FileOutputStream - 实现了对文件的读写操作
ObjectInpuStream / ObjectOutputStream - 实现了对序列化对象的读写操作
ByteArrayInputStream / ByteArrayOutputStream - 实现了对字节数组的读写操作
PipedInputStream / PipedOutputStream - 实现不同线程之间的通信
SequenceInputStream - 实现不同输入流的合并(此对象没有对应的OutputStream类)
BufferedInputStream / BufferedOutputStream - 实现读写缓存层
1、字节流读取 - byte(表示读取的数据类型是byte或byte[])
//15.字节流读取 - byte @Test public void readByte(){ try{ File file = new File("hello.txt"); InputStream fos = new FileInputStream(file); byte[] bytes = new byte[fos.available()]; fos.read(bytes); String str = new String(bytes); System.out.println("文件内容是:\n" + str); fos.close(); }catch(Exception e){ e.printStackTrace(); } }
2、字节流读取(缓存) - byte
//字节流读取(缓存) - byte @Test public void writeByteWithBuffere(){ try{ File file = new File("hello1.txt"); OutputStream fos = new FileOutputStream(file); BufferedOutputStream out = new BufferedOutputStream(fos); out.write("你好\n".getBytes()); out.write("吃饭了么!".getBytes()); out.flush(); fos.close(); }catch(Exception e){ e.printStackTrace(); } }
3、字节流写入 - byte
//17.字节流写入 - byte @Test public void writeByte(){ try{ File file = new File("hello.txt"); OutputStream fos = new FileOutputStream(file); fos.write("Hello Mac.\n你好,Mac.".getBytes()); fos.close(); }catch(Exception e){ e.printStackTrace(); } }
4、字节流写入(缓存) - byte
//18.字节流写入(缓存) - byte @Test public void writeByteWithBuffer(){ try{ File file = new File("hello.txt"); OutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write("Hello Mac.\n你好,Mac.".getBytes()); bos.close(); fos.close(); }catch(Exception e){ e.printStackTrace(); } }
如果你仔细敲过上面4个例子的代码你会发现,其实好像字节流的读取和写入,好像加了缓存和没加缓存,它们的代码好像都差不多啊,至少再写入数据的时候是一样的。而字符流的读取在加了缓存层之后,至少还能直接读取整行数据,字符流的写入加了缓存之后,可以写入换行符。那字节流的缓存究竟有什么必要性呢?
确实,从代码以及其方法上看,其实他们并没有什么区别,但是从官方的API文档来看,缓存最重要的一个地方就是减少程序对于磁盘的IO次数。加了缓存的程序再读取的时候会一次性读取很多个字节,之后提供给程序使用,但如果你不加缓存,那么程序就只会读取代码中指定的字节数。这在你一个字节一个字节从文件中读取数据的时候,其差别就凸现出来了。如果你没有使用缓存进行数据读取,那么你每读一个字节的数据,程序就去磁盘读取一次文件,这样会造成磁盘的频繁IO读取,减少磁盘的寿命。
5、ObjectInputStream / ObjectOutputStream - 序列化一个对象
要被序列化的POJO对象:
package com.chanshuyi.io.po; import java.io.Serializable; public class Student implements Serializable{ /** * 序列化ID */ private static final long serialVersionUID = 7288449352920655248L; private String name; private int age; private String phone; public Student(){ } public Student(String name, int age, String phone){ this.name = name; this.age = age; this.phone = phone; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String toString(){ return name + "," + age + "," + phone; } }
被序列化的POJO对象需要实现Serializable接口。
序列化对象方法:
//20.ObjectOutputStream - 序列化对象 - 将对象属性序列化保存 @Test public void serialized(){ try{ Student std = new Student("Tommy", 13, "18923923876"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("StudentObject.obj")); oos.writeObject(std); oos.close(); }catch(Exception e){ e.printStackTrace(); } }
反序列化对象方法:
//21.ObjectInputStream - 反序列化对象 - 读取序列化后的对象 @Test public void deSerialized(){ try{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("StudentObject.obj")); Student std = (Student)ois.readObject(); System.out.println(std); ois.close(); }catch(Exception e){ e.printStackTrace(); } }
6、ByteArrayInputStream / ByteArrayOutputStream - 操作内存字节数据
//19.ByteArrayInputStream - 内存操作流 - 将内存数据转化为流 @Test public void random2Stream(){ try{ String str = "你好"; 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 outputStr = output.toString(); input.close(); output.close(); System.out.println(outputStr); }catch(Exception e){ e.printStackTrace(); } }
7、PipedInputStream / PipedOutputStream - 实现进程间的管道通信
接收者:
package com.chanshuyi.io.pineStream; import java.io.PipedInputStream; /** * 管道流 - 接收者 * @author yurongchan * */ public class Receiver implements Runnable{ private PipedInputStream in = null; public Receiver(){ in = new PipedInputStream(); } public PipedInputStream getIn(){ return this.in; } public void run(){ byte[] b = new byte[1000]; int length = 0; try{ length = this.in.read(b); }catch(Exception e){ e.printStackTrace(); } System.out.println("接收到的消息:" + new String(b, 0, length)); } }
发送者:
package com.chanshuyi.io.pineStream; import java.io.PipedOutputStream; /** * 管道流 - 发送者 * @author yurongchan * */ public class Send implements Runnable{ private PipedOutputStream out = null; public Send(){ out = new PipedOutputStream(); } public PipedOutputStream getOut(){ return this.out; } public void run(){ String msg = "Hello, I'm outputer.\n你好,我是发送者。"; try{ out.write(msg.getBytes()); out.close(); }catch(Exception e){ e.printStackTrace(); } } }
测试方法:
//22.PipedInputStream - 在不同线程之间进行通信 @Test public void pipeContact(){ try{ Send send = new Send(); Receiver receiver = new Receiver(); try{ send.getOut().connect(receiver.getIn()); }catch(Exception e){ e.printStackTrace(); } new Thread(send).start(); new Thread(receiver).start(); }catch(Exception e){ e.printStackTrace(); } }
8、SequenceInputStream - 合并输入流
//23.SequenceInputStream - 合并几个输入流 @Test public void sequenceInputStream(){ try{ InputStream is1 = new FileInputStream(new File("sequence1.txt")); InputStream is2 = new FileInputStream(new File("sequence2.txt")); OutputStream os = new FileOutputStream(new File("sequence3.txt")); SequenceInputStream sis = new SequenceInputStream(is1, is2); int temp = 0; while((temp = sis.read()) != -1){ os.write(temp); } sis.close(); is1.close(); is2.close(); os.close(); }catch(Exception e){ e.printStackTrace(); } }
之后打开sequence3.txt会发现,1、2文本中的内容都到了sequence3.txt中了。
四、字符流读写
字符流的读写实际上还是基于字节流实现的,而且数组存储时更多是以字节为单位存储,因此更多时候还是使用字节流进行读写操作。
因此对于字符流的读写,我们只需要掌握常用的几个操作即可。
InputStreamReader / OutputStreamWriter - 实现字符流的读写
BufferedReader / BufferedWriter - 实现字符流的缓存层
FileReader / FileWriter - 字符流的工具类
1、字符流读取 - char(表示读取的数据类型是char或char[])
//9.字符流读取 - char @Test public void writeChar(){ try{ InputStreamReader reader = new InputStreamReader(new FileInputStream("OutputStreamWriter.txt")); char[] chars = new char[1000]; int length = reader.read(chars); System.out.println("一共读取了" + length + "个字符,内容是:" + new String(chars)); reader.close(); }catch(Exception e){ e.printStackTrace(); } }
2、字符流读取(缓存) - char
//10.字符流读取(缓存) @Test public void writeCharWithBuffer(){ try{ InputStreamReader isr = new InputStreamReader(new FileInputStream("BufferedWriter.txt")); BufferedReader reader = new BufferedReader(isr); String str = ""; while((str = reader.readLine()) != null && str.length() != 0){ System.out.println(str); } reader.close(); }catch(Exception e){ e.printStackTrace(); } }
3、字符流写入 - char / char[] / String
//11.字符流写入 @Test public void readChar(){ try{ OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("OutputStreamWriter.txt")); writer.write("AllFileTest.fileReadUtil -> 字符流写入文件"); writer.close(); }catch(Exception e){ e.printStackTrace(); } }
4、字符流的写入(缓存)- char/ String
//12.字符流写入(缓存) @Test public void readCharWithBuffer(){ try{ OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("BufferedWriter.txt")); BufferedWriter writer = new BufferedWriter(osw); writer.write("AllFileTest.fileReadUtil -> 字符流写入文件"); writer.newLine(); //换行 writer.write("第二行"); writer.close(); }catch(Exception e){ e.printStackTrace(); } }
总结一下上面四种方式的字符流写入写出,我们会发现两个规律,一个是读写规律,一个是缓存层的规律:
· 读写规律。字符流的读取,其读取的数据都是char(字符型)的单个或者数组。而字符流的写入除了可以写入单个或多个char类型的字符歪,还可以直接写入String(字符串)类型。
· 缓存层规律。字符流的读写,增加了缓存层之后的一个明显区别就是:加了缓存层(Buffer)之后,字符流读取可以实现整行读取(readLine),而字符流写入可以实现写入换行符(writeLine)。
5、文件读取工具类
//13.FileReader - 文件读取工具类(这是加了缓存的。但也可以不加缓存) @Test public void fileReadUtil(){ try{ FileReader fr = new FileReader(new File("demo.txt")); BufferedReader reader = new BufferedReader(fr); String str = ""; while((str = reader.readLine()) != null && str.length() != 0){ System.out.println(str); } reader.close(); }catch(Exception e){ e.printStackTrace(); } }
将这个例子与上面的第2个例子,即加了缓存的字符流读取例子相比,你会发现其实这两个例子的区别就只是声明FileReader、InputStreamReader的区别而已。声明FileReader只需要再加上File类型参数即可,而声明InputStreamReader则需要再加上一个FileInputStream类,之后才能跟上File类型的参数。因此,我们才说FileReader是一个文件读取工具类。
6、文件写入工具类
//14.FileWriter - 文件写入工具类(这是加了缓存的。但也可以不加缓存) @Test public void fileWriteUtil(){ try{ FileWriter fw = new FileWriter(new File("FileWriteUtil1.txt")); BufferedWriter writer = new BufferedWriter(fw); writer.write("HelloMan1"); writer.newLine(); writer.write("HelloMan2"); writer.close(); }catch(Exception e){ e.printStackTrace(); } }
同样的,其实FileWriter与OutputStreamWriter也只是声明上的区别而已。
五、其他
这里会收集一些不怎么常用,但是有时也会用到的例子,遇到的时候可以快速的查询到。
1、追加新的内容
//9.字节流 - 追加新内容 //无论是字节流还是字符流,要追加新的内容都是再FileOutputStream中指定第二个参数为true @Test public void appendFile(){ try{ File file = new File("hello.txt"); OutputStream fos = new FileOutputStream(file, true); String str = "\n这是新增加的内容"; fos.write(str.getBytes()); fos.close(); }catch(Exception e){ e.printStackTrace(); } }
2、模拟打印流输出数据
//18.打印流 - 模拟打印的方式输出数据 @Test public void printStream(){ try{ PrintStream print = new PrintStream(new FileOutputStream(new File("PrintStream.txt"))); print.println(true); print.println("您好,我是打印输出流"); print.printf("名字:%s.年龄:%d", "Tom", 32); //格式化输出 print.close(); //这里的数据要再PrintStream.txt文件中才能看到 }catch(Exception e){ e.printStackTrace(); } }
3、使用OutputStream向屏幕输出内容
//19.使用OutputStream向屏幕输出内容 @Test public void systemOutStream(){ try{ OutputStream out = System.out; out.write("你好".getBytes()); out.close(); }catch(Exception e){ e.printStackTrace(); } }
4、标准输出重定向
//20.标准输出重定向 @Test public void redirectOutput(){ try{ System.out.println("Print in the Screen. 你好"); System.setOut(new PrintStream(new FileOutputStream(new File("RedirectOutput.txt")))); //下面的输出都将重定向到文件中 System.out.println("=== 重定向后的输出 ==="); System.out.println("Hello, Eclipse in Mac."); }catch(Exception e){ e.printStackTrace(); } }
5、标准输入重定向
//21.标准输入重定向 @Test public void redirectInput(){ try{ File file = new File("RedirectOutput.txt"); if(!file.exists()){ System.out.println("文件不存在!"); return; }else{ System.setIn(new FileInputStream(file)); byte b[] = new byte[1000]; int length = System.in.read(b); System.out.println("读入的内容为:" + new String(b, 0, length)); } }catch(Exception e){ e.printStackTrace(); } }
6、错误输出重定向
//22.错误输出重定向 @Test public void redirectErrOutput(){ try{ System.err.println("Print in the Screen. 你好"); System.setErr(new PrintStream(new FileOutputStream(new File("RedirectErrOutput.txt")))); //下面的输出都将重定向到文件中 System.err.println("=== 重定向后的错误输出 ==="); System.err.println("Hello, Eclipse in Mac."); }catch(Exception e){ e.printStackTrace(); } }
感谢以下博文的参考:
1、http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html
2、http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html
2.熟悉Java基本类库系列——Java IO 类库的更多相关文章
- Java面试题系列 ----- Java基础面试题(91道)
更多详情点击查看,点这里!这里!!这里!!! 文末获取所有面试PDF文档! Java概述 1. 何为编程 编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程. 为了 ...
- 4.熟悉Java基本类库系列——Java 正则表达式类库
正则表达式语法结构图: Java正则表达式类库结构图: Java典型例子 1.String类 matches()方法 判断字符串是否符合特定正则表达式 @Test public void testRe ...
- Java问题解读系列之IO相关---Java深拷贝和浅拷贝
前几天和棒棒童鞋讨论Java(TA学的是C++)的时候,他提到一个浅拷贝和深拷贝的问题,当时的我一脸懵圈,感觉自己学Java居然不知道这个知识点,于是今天研究了一番Java中的浅拷贝和深拷贝,下面来做 ...
- 1.熟悉Java基本类库系列 - 目录
写这个系列是想让自己多熟悉熟悉Java的基本类库,忘记的时候可以在这里看看之前写过的例子,这样就可以很快的回忆起来如何使用了. 这样就可以很节省时间了. ======= 下面是传送门啦 ======= ...
- java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能
这是java高并发系列第14篇文章. 本文主要内容: 讲解3种让线程等待和唤醒的方法,每种方法配合具体的示例 介绍LockSupport主要用法 对比3种方式,了解他们之间的区别 LockSuppor ...
- java高并发系列 - 第17天:JUC中的循环栅栏CyclicBarrier常见的6种使用场景及代码示例
这是java高并发系列第17篇. 本文主要内容: 介绍CyclicBarrier 6个示例介绍CyclicBarrier的使用 对比CyclicBarrier和CountDownLatch Cycli ...
- java高并发系列 - 第13天:JUC中的Condition对象
本文目标: synchronized中实现线程等待和唤醒 Condition简介及常用方法介绍及相关示例 使用Condition实现生产者消费者 使用Condition实现同步阻塞队列 Object对 ...
- java高并发系列 - 第2天:并发级别
由于临界区的存在,多线程之间的并发必须受到控制.根据控制并发的策略,我们可以把并发的级别分为阻塞.无饥饿.无障碍.无锁.无等待几种. 阻塞 一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继 ...
- java基础解析系列(三)---HashMap
java基础解析系列(三)---HashMap java基础解析系列 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)-- ...
随机推荐
- BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)
首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...
- java dbutils查询数据库时无法给部分字段赋值原因
1,javaBean如下: public class User { /** * 用户唯一标识(ID) */ private String uid; /** ...
- 原生js和jquery实现图片轮播特效(转)
本文给大家分享的是使用原生JS和JQ两种方法分别实现相同的图片轮播特效,十分的实用,也非常方便大家对比学习原生js和jQuery,有需要的小伙伴可以参考下. 1)首先是页面的结构部分对于我这种左右切换 ...
- java读取文件方法总结
由于最近在做一个关于从手机本地读取格式化的txt文件中的内容,并且把内容放在listview中显示.这样问题来了,就是如何能够遍历已经获取到特定的map中就是一个问题,在网上找了一些资料,找到了一个很 ...
- Jemter+Badboy实战经验一(Badboy录制及基础功能)
1. 使用工具: Apache Jemeter:http://jmeter.apache.org/download_jmeter.cgi (免费官网下载地址) BadBoy: http://www ...
- Java 注解 入门
这几天在学习Spring3.x,发觉现在许多框架都用上了java注解功能,然后自己就对java注解这方面初步学习了一下. 首先,注解跟注释不是一个意思,也根本不是同一个事物. 注释就是我们平常平常中对 ...
- Azure Messaging-ServiceBus Messaging消息队列技术系列4-复杂对象消息是否需要支持序列化和消息持久化
在上一篇中,我们介绍了消息的顺序收发保证: Azure Messaging-ServiceBus Messaging消息队列技术系列3-消息顺序保证 在本文中我们主要介绍下复杂对象消息是否需要支持序列 ...
- 常见的html面试题
1.doctype作用?标准模式和兼容模式各有什么区别? (1).<doctype>声明位于文档第一行,在<html>标签之前.用于告知浏览器的解析器以什么样的标准解析该文档. ...
- 1708: [Usaco2007 Oct]Money奶牛的硬币
1708: [Usaco2007 Oct]Money奶牛的硬币 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 544 Solved: 352[Submi ...
- ImportError: No module named cv2 解决方法
ImportError: No module named cv2 解决方法 import cv2时会出现这个问题 解决方法:将openCV安装目录里的python文件夹内的cv2.pyd复制到Py ...