Java 文件 IO 详解(下)
来源:互联网 发布:广告位管理系统源码 编辑:程序博客网 时间:2024/05/21 08:35
Java 文件 IO 详解(下)
在“Java IO详解(上)”这个文章里面我们明确了输入/输出流的4个基类,并且详细了解了4个访问节点流的用法。接下来我们使用跟简单的处理流来访问文件。
1. 处理流的用法
使用处理流的思路是:通过处理流来包装节点流,程序通过处理流来执行输入/输出功能,让节点流与底层的 I/O设备、文件交互。
处理流非常简单,只要流的构造器不是一个物理节点,而是已经存在的流,那这个流就一定是处理流。而节点流都是直接以物理节点作为构造器参数的。下面通过PrintStream处理流来包装OutputStream,感受下处理流的简便:
/** * Created by 杨Sir on 2017/10/30. * 处理流的用法:只需在创建处理流时传入节点流即可 */public class PrintStreamTest { public static void main(String[] args){ try ( //创建文件输出流,,节点流 FileOutputStream fos = new FileOutputStream("PrintStreamTest.txt"); //创建处理流 PrintStream ps = new PrintStream(fos)) { //使用 PrintStream执行输出 ps.println("普通字符串"); //直接使用 PrintStream 输出对象 ps.println(new PrintStreamTest()); } catch (IOException e) { e.printStackTrace(); } }}
通常如果需要输出文本内容,都应该将输出流包装为PrintStream后进行输出。使用了处理流包装了底层节点流后,关闭输入/输出资源时只需要关闭上层处理流即可,底层节点流会自动关闭。
2. 输入/输出流体系
Java 输入/输出流体系提供了40多个类,但却很有规律。 我们来看一看:
注:上面的粗体代表节点流,必须直接与物理节点相连;斜体代表抽象基类,无法创建实例。
通常情况下:如果输入/输出的内容是文本内容,则考虑使用处理流,如果进行输入/输出是二进制文件,那么使用节点流。能用记事本打开的称为文本文件,否则为二进制文件。
字符流还有一个好处就是可以把字符串当做是一个物理节点,用于从字符串读取内容,获将内容写入字符串(用StringBuffer充当字符串)的功能。我们用程序见证一下字符串作为物理输入/输出节点:
/** * Created by 杨Sir on 2017/10/31. * 使用字符串作为物理节点的字符输入/输出流的用法 * * 以字符串作为物理节点时,使用 StringReader和StringWriter进行访问字符串, * StringWriter写入字符串其实是将字符串写在StringBuffer中,用StringBuffer充当字符串。 */public class StringNodeTest { public static void main(String[] args) { String src = "既然4个基类访问文件的节点流比较\n" + "麻烦,那么我们来看看如何使用处理流操\n" + "作文件。处理流可以隐藏底层节点流之间\n" + "的差异,想外提供更加方便的输入输出方法。\n"; char[] buf = new char[32]; int hasRead = 0; try ( StringReader sr = new StringReader(src)) { while ((hasRead = sr.read(buf)) > 0) { System.out.println(new String(buf, 0, hasRead)); } } catch (IOException e) { e.printStackTrace(); } /** StringWriter 底层的部分代码。 public StringWriter(int initialSize) { buf = new StringBuffer(initialSize); lock = buf; } */ try ( //创建指定的 StringWriter,实际上以一个 StringBuffer 作为输出节点。 StringWriter sw = new StringWriter(20)) { //调用StringWriter的方法执行输出 sw.write("用处理流来包装节点流,\n"); sw.write("程序通过处理流来进行输入输出,\n"); sw.write("通过节点流与底层的I/O设备进行,\n"); sw.write("如何识别处理流,\n"); System.out.println("-------下面是 sw 字符串节点的内容------"); System.out.println(sw.toString()); }catch (IOException e){ e.printStackTrace(); } }}
- 转换流
I/O 体系提供了两个转换流将字节流转为字符流,InputStreamReader和OutputStreamWriter;我以获取键盘输入为例介绍下转换流的用法,Java的System.in代表标准输入,这个标准输入流是InputStream类的实例,键盘输入都是文本内容。
/** * Created by 杨Sir on 2017/10/31. * 装换流: InputStreamReader:将字节输出流转换为字符输出流; OutputStreamReader:将字节输出流转换为字符输出流。 * * BufferedReader流具有缓冲的功能,可以逐行读取,以换行符为标致,没有读到换行符,则程序阻塞,直到读到换行符。 */public class KeyinTest { public static void main(String[] args){ try( // System.in 标准输入流是InputStream的类的实例。因此可以将 System.in 转换为 Reader对象 InputStreamReader reader = new InputStreamReader(System.in); //将普通的Reader包装为 BufferedReader BufferedReader br = new BufferedReader(reader)) { String line = null; //采用循环的方式逐行读取 while((line = br.readLine()) != null){ //如果程序读到 "exit",则程序退出 if(line.equals("exit")){ System.exit(1); } //打印读取内容 System.out.println("输入内容为:"+line); } }catch(IOException e){ e.printStackTrace(); } }}
BufferReader流具有缓冲能力,他还可以一行一行读取文本,以换行符为标志,如果没有读到换行符,则程序阻塞。
4. 推回输入流
在I/O 体系,有两个流很与众不同,就是PushbackInputStream和 PushbackReader,他们都提供了三个方法:
void unread(byte[]/char[] buf): 将一个字节或字符数组内容推回到缓冲区,从而允许重复读取刚才的内容。
void unread(byte[]/char[] buf, int off, int len): 将一个字节/字符数组从off开始,长度为len 字节/字符的内容推回到缓冲区,从而允许重复读取刚刚的内容。
void unread(int b): 将一个字节或字符内容推回到缓冲区,从而允许重复读取刚才的内容。
废话不多说,直接看例子:
/** * Created by 杨Sir on 2017/10/31. * 推回输入流:PushbackInputStream 和 PushbackReader,两个推回输入流都带有一个推回缓冲区。推回时会将指定数组内容推回到缓冲区, * 读取时先读取推回到缓冲区中的数据,推回缓冲区内容不够时才从原输入流中读取。推回缓冲区长度默认为 1。 * * 该程序功能:找出 "new FileReader" 字符串,输出该字符串之前的内容 */public class PushbackTest { public static void main(String[] args){ try( //创建一个PushbackReader对象,指定推回缓冲区长度为64 PushbackReader pr = new PushbackReader(new FileReader("D:\\绝对路径PushbackTest.java"),64)) { char[] buf = new char[32]; //用以保存上次读取的字符串内容 String lastContent = ""; int hasRead = 0; //循环读取文件内容 while((hasRead = pr.read(buf))>0){ //将读取内容转换为字符串 String content = new String(buf, 0, hasRead); int targetIndex = 0; //将上次读取的字符串和这次的连接起来,查看是否包含目标字符串 if((targetIndex = (lastContent+content).indexOf("new FileReader")) > 0){ //将本次内容和上次内容以前推回缓冲区 pr.unread((lastContent+content).toCharArray()); //重新定义一个长度为 targetIndex的数组 if(targetIndex > 32){ buf = new char[targetIndex]; } //再次读取指定长度的内容 pr.read(buf, 0, targetIndex); //打印读取的内容 System.out.println(new String(buf, 0, targetIndex)); System.exit(0); }else{ //打印上次读取的内容,只要没匹配成功,就打印出上次读取的内容,, //匹配成功后只需打印出 匹配成功的那次的上一次到目标字符串之前 的内容即可。 System.out.println(lastContent); lastContent = content; } } }catch (IOException e){ e.printStackTrace(); } }}
- 重定向标准输入/输出
Java的标准输入/输出分别通过System.in 和 System.out代表,默认情况下是 键盘和显示器。
重定向标准输入/输出: System类里提供了三个重定向标准输入/输出的方法
– static void setErr(PrintStream err): 重定向“标准”错误输出流
– static void setIn(InputStream in): 重定向”标准”输入流
– static void setOut(OutputStream out): 重定向“标准”输出流。
例如:重定向标准输出流,将System.out 输出重定向到文件输出
/** * Created by 杨Sir on 2017/10/31. */public class RedirectOut { public static void main(String[] args){ try( //一次性创建PrintStream输出流 PrintStream ps = new PrintStream(new FileOutputStream("out.txt"))) { //将标准输出流重定向到ps输出流,,sout的输出将由控制台转到 ps的输出流 System.setOut(ps); //向标准输出 输出一个字符串 System.out.println("普通字符串"); //向标准输出 输出一个对象 System.out.println(new RedirectOut()); } catch (FileNotFoundException e) { e.printStackTrace(); } }}
- RandomAccessFile(任意位置访问文件)
RandomAccessFile是Java输入输出体系中功能最丰富的文件内容访问类,提供了很多方法访问文件内容,既可以读取文件内容,也可以像文件输出数据,可以是任意位置。它的缺点是只能读写文件,不能读写其他IO节点。
RandomAccessFile提供了两个方法操作文件记录指针:
long getFilePointer(): 返回文件记录指针当前的位置。
void seek(long pos): 将文件记录指针定位到pos位置。
RandomAccessFile的读写文件的方法完全类似于InputStream和OutputStream的read方法和write方法。
RandomAccessFile 有两个构造器,一个使用String参数指定文件名,一个使用File参数指定文件本身;除此之外还要指定一个 mode参数,该参数确定RandomAccessFile的访问方式。
“r”: 以只读的方式打开指定文件。
“rw”: 以读、写的方式打开指定文件。
“rws”:以读、写的方式打开指定文件,相对于“rw”,还要求对文件内容或元数据的每个更新都同步写到底层存储设备。
“rwd”: 以读、写的方式打开指定文件,相对于“rw”,还要求对文件内容的每个更新都同步写到底层存储设备。
还是来个实例爽快,功能:向指定文件的指定位置后面追加内容,为防止覆盖,先要创建一个临时文件保存指定位置后面的数据,插入要插的内容以后,再将临时文件里的内容追加到插入后的内容的后面:
/** * Created by 杨Sir on 2017/11/1. * 向指定文件、指定位置插入内容,,并且不覆盖指定位置后面的内容 * */public class InsertContent { public static void main(String[] args) throws IOException { insert("out.txt", 5,"恩恩haha我是插入的内容\r\n"); } public static void insert(String filename , long pos , String content) throws IOException { //创建临时文件 File tmp = File.createTempFile("emp",null); //默认后缀为 .tmp tmp.deleteOnExit(); try( RandomAccessFile raf = new RandomAccessFile("D:\\IDEARep\\CrazyJavaLiGang\\"+filename,"rw"); //使用临时文件来保持插入点后的数据 FileInputStream tmpfis = new FileInputStream(tmp); FileOutputStream tmpfos = new FileOutputStream(tmp); ) { raf.seek(pos); //--------将插入点后的数据保持在临时文件 byte[] buf = new byte[64]; int hasRead = 0; while((hasRead = raf.read(buf)) > 0){ tmpfos.write(buf, 0, hasRead); } //插入内容 raf.seek(pos); raf.write(content.getBytes()); //追加临时文件中的内容 while((hasRead = tmpfis.read(buf)) > 0 ){ raf.write(buf, 0 ,hasRead); } }catch (IOException e){ e.printStackTrace(); } }}
- Java 文件 IO 详解(下)
- java中的IO详解(下)
- java中的IO详解(下)
- java IO流详解(下)
- Java io详解(-)
- 详解Java 流(Stream)、文件(File)和IO(一)
- java IO详解(转)
- java IO详解(二)
- JAVA IO详解(转)
- java文件读写(IO)
- Android文件IO详解
- Android文件IO详解
- Android文件IO详解
- Android文件IO详解
- java io (java输入输出流)详解
- java io流对文件的操作详解
- java学习笔记之文件IO流详解
- Java IO详解——随机访问文件流
- 打造丝般顺滑的 H5 翻页库
- 【Ionic】常用小模块及经验总结
- Stream详解
- Spring-boot 坑
- 一段根据后台内容动态合并单元格的代码
- Java 文件 IO 详解(下)
- table 中信息上下左右 居中
- 2017.11.02 loli的模拟赛
- 11.2
- 安卓属相动画练习一
- unity 3d EasyTouch(二)
- 第八章 java常用类库
- android 按键 添加
- Okhttp解析(一)请求的分发,拦截