Java的I/O是一个庞大的文件操作系统,初学者往往对I/O的使用比较迷茫,优点丈二和尚摸不着头脑的感觉。即便是使用java I/O处理了自己的实际需求仍然不知其所以然。当然我也是这样,所以几天以前我决定好好地看看java的I/O系统,到现在感觉还行,当然用好不敢自夸,但是对于I/O的那个套路差不多已经走通了,并不像以前那样云里雾里不知所云了。我学习的资料是《java编程思想》,这个总结并没有多少我自己的东西,因为我的水平有限,倒是想自己造一个轮子但是毕竟能力有限吗。

好了废话不多说了,我下面说一下我的学习思路,只是一个思路,当然我已经按照这个路子能比较清楚的使用java的I/O了,所以当大家发现这都是我摘抄的编程思想的内容是大家不要诧异,欢迎拍砖...

先来说一下File类。File类一个容易让我们"顾名思义"的类。通常我们看到这个类,就会想到这个类可能指代的是一个文件。但是实际上不是这样子的,他指的是一组文件名或单个文件名。Java API上面说:"文件和目录路径名的抽象表示形式"。我们先来看一段简单的代码就可以一目了然了,心中的疑惑就烟消云散了:

package review;

import java.io.File;

public class TestFile {

public static void main(String[] args) {

File file = new File("D://test.txt");

System.out.println(file);

System.out.println(file.isFile());

}

}

Result:

D:\test.txt

true

让我们看一下输出地结果,当我们打印file对象的时候输出了一个window下的文件路径,第二个打印结果是true。当然我提前已经在D盘创建了这个test.txt文件,第二个输出地意思是这个test.txt对象是不是在D盘下面。我们稍微看一下File类的源码也可以看到设计者设计File类的意图:

public class File

implements Serializable, Comparable

{

...

private String path;

...

/**

* Creates a new File instance by converting the given

* pathname string into an abstract pathname. If the given string is

* the empty string, then the result is the empty abstract pathname.

*

* @param pathname A pathname string

* @throws NullPointerException

* If the pathname argument is null

*/

public File(String pathname) {

if (pathname == null) {

throw new NullPointerException();

}

this.path = fs.normalize(pathname);

this.prefixLength = fs.prefixLength(this.path);

}

/**

* Converts this abstract pathname into a pathname string. The resulting

* string uses the {@link #separator default name-separator character} to

* separate the names in the name sequence.

*

* @return The string form of this abstract pathname

*/

public String getPath() {

return path;

}

/**

* Returns the pathname string of this abstract pathname. This is just the

* string returned by the {@link #getPath} method.

*

* @return The string form of this abstract pathname

*/

public String toString() {

return getPath();

}

看了这样的一部分源码我们对File类的大概用途差不多已经知道了。首先声明了一个String类型的path对象,在File的构造方法中有对path的赋值,toString方法也是返回了getPath()取得path值,FIle类一直在和String类型的path对象打交道,所以,这个File类的功能我们也大概知道了。至于具体的File如何使用,如何创建一个目录,如何打印一个目录就没必要举例了吧!自己对照着API实验吧。不过我们要注意一下FilenameFiter这个类,他的用法下面举了一个例子:

package org.wk.io;

import java.io.File;

import java.io.FilenameFilter;

import java.util.Arrays;

import java.util.regex.Pattern;

/**

* 作用:初探File类,获取文件名称的小工具类,并检查某个文件名称是否在此文件集合中

*/

public class DirectoryList {

public static void main(String[] args) {

File path = new File(".");

String list[] = null;

if (args.length == 0) {

list = path.list();

} else

list = path.list(new DirFilter(args[0]));

Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);

for(String str : list) {

System.out.println("File Name: " + str);

}

}

}

class DirFilter implements FilenameFilter {

private Pattern pattern;

public DirFilter(String regex) {

this.pattern = Pattern.compile(regex);

}

@Override

public boolean accept(File dir, String name) {

return pattern.matcher(name).matches();

}

}

下面是比较核心的部分,也是为什么我们在使用java I/O的时候比较迷惑的地方---java的输入输出流。

关于流的概念:它代表任何有能力产出数据的数据源对象或者有能力接受数据的接收端对象,"流"屏蔽了实际I/O设备中处理数据的细节。实际上是为用户提供了接口,用户只需关心使用"流"就行了,不必在操心数据的处理。

Java的I/O流分成输入和输出两大部分,但是输入和输出又有基于字符和字节之分,那我们就具体展开来看一下其中的细节。

基于字符的输入和输出:

输入流:任何由InputStream派生的类,他们均包含read()方法。

输出流:任何有OutputStream派生的类,他们均包含write()方法。

FileInputStream类型

功能

构造器

如何使用

ByteArrayInputStream

允许将内存的缓冲区当做InputStream使用。关闭 ByteArrayInputStream无效,此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。

缓冲区,字节将从中取出作为数据源;配合FilterInputStream对象使用提供有用的接口。

StringBufferInputStream

将String对象转换成InputStream

字符串,底层实现实际使用StringBuffer作为数据源;配合FilterInputStream对象使用提供有用的接口。

FileInputStream

用于从文件中读取信息

字符串,表示文件名,或FileDescriptor对象作为一种数据源;配合FilterInputStream对象使用提供有用的接口。

PipedInputStream

产生用于写入相关PipedOutputStream的数据。实现了"管道化"的概念。

PipedOutputStream作为多线程中数据源;配合FilterInputStream对象使用提供有用的接口。

SequenceInputStream

将两个或多个InputStream对象转换成为一个InputStream。

两个InputStream或者一个容纳InputStream的Enumeration作为一种数据源;配合FilterInputStream对象使用提供有用的接口。

FilterInputStream

抽象类,作为装饰器的接口。其中为其他的InputStream提供有用的接口。

详细建见表"FileterInputStream类型"。

OutputStream类型

功能

构造器

如何使用

ByteArrayOutputStream

在内存中创建缓冲区,所有送往"流"的数据都要放置在此缓冲区中。

缓冲区初始化大小(可选),用于指定数据的目的地;配合FilterOutputStream对象使用提供有用的接口。

FileOutputStream

用于将信息写至文件

字符串,表示文件名,文件或FileDescriptor对象指定数据的目的地;配合FilterOutputStream对象使用提供有用的接口。

PipedOutputStream

任何写入其中的信息都会自动作为相关PipedInputStream的输出。实现"管道化"概念。

PipedOutputStream指定用于多线程的数据目的地;配合FilterOutputStream对象使用提供有用的接口。

FilterOutputStream

抽象类,作为装饰器的接口。其中为其他的OutputStream提供有用的接口。

见表"FilterOutputStream类型"。

前面的表中有好多的地方在卖关子,什么装饰器类的接口,什么配合FilterInputStream提供有用的接口。装饰器类式设计模式中比较重要和常用的一种设计模式,可以上网上搜一下了解一下装饰器模式。装饰器模式的特点之一是比较灵活这也导致了我们在使用java I/O的时候比较困惑。BufferedInputStream buffer = new BufferedInputStream(...);里面的内容我们到底如何决定呢,正是装饰器模式给我们带来了这种麻烦。那我们看看这两个装饰器类的子类到底有什么也方便我们的选择。

FileterInputStream类型

功能

构造器参数

如何使用

DataInputStream

与DataOutputStream搭配之用,因此我们可以按照可移植的方式读取基本类型。

InputStream

包含用于读取基本数据类型的全部接口。

BufferInputStream

使用它可以防止每次读取都进行实际写操作,代表使用缓冲区。

InputStream可以指定缓冲区大小

本质上不提供接口只不过是向进程中添加缓冲区是必需的。与接口对象搭配。

LineNumInputStream

跟踪输入流中的行号;可调用getLineNum(),setLineNum()。

InputStream

仅增加了行号,与接口对象搭配之用。

PushBackInputStream

具有"能弹出一个子节的缓冲区"的功能,因此可以将读到的最后一个字符回退。

inputStream

通常最为编译器的扫描器,之所以包含在内是因为java编译器的需要,我们可能不会用到。

所以,如果我们通常这样写程序

BufferedInputStream b = new BufferedInputStream(new DataInputStream(new FileInputStream("xxx")));

如果对装饰器模式稍微有点了解的话,就会很容易理解这段程序。首先new FileInputStream("xxx") 作为DataInputStream 的构造器参数new DataInputStream(new FileInputStream("xxx")) 又作为BufferedInputStream  的构造参数,非常明显的装饰器模式。

我们再来看一下FilterOutputStream的实现类

FilterOutputStream类型

功能

构造器参数

如何使用

DataOutputStream

与DataIntputStream搭配之用,因此我们可以按照可移植的方式读取基本类型。

OutputStream

包含用于读取基本数据类型的全部接口。

PrintStream

用于产生格式化输出。其中DataOutputStream处理存储,PrintStream处理显示。

OutputStream,可以用boolean值表示在每次换行的时候是否清空缓冲区

BufferedOutputStream

使用它可以防止每次读取都进行实际写操作,代表使用缓冲区。代表使用缓冲区,可以用flush()清空缓冲区

OutputStream,指定缓冲区大小

本质上不是接口,只不过是向进程中添加缓冲区所必需的。与接口搭配之用。

所以,类比输入流的程序我们可以这样写:

DataOutputStream d = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("...")));

道理与输入流一样,所以两者掌握一个另一个也就可以掌握了,但是并不是所有的输入和输出流的API都是有对应的,灵活掌握才是硬道理。

基于字节流的输入输出:

Reader和Writer两个类的操作是基于字符,提供兼容Unicode的功能,同时也起到国际化的作用。但是这两个类又不是完全没有关联的,我们可以通过适配器模式将InputStream转换成为Reader,这个适配器类就是InputStreamReader;同样我们可以通过适配器类OutputStreamWriter将OutputStream转换成为Writer。

这样我们在操作文件的时候就拥有了两个利器,一个是面向字节的InputStream,OutputStream;和面向字符的Reader,Writer。那么究竟什么情况下使用Reader,Writer,什么情况下使用InputStream,OutputStream呢?由于Reader和Writer是后来添加上的类,所以它的操作效率比InputStream和OutputStream高,于是在编程思想中给出了这样的结论:尽量常识使用Reader和Writer,一旦程序无法成功的编译,那是在选择InputStream和OutputStream。

下面我们看一下这两个类层次结构的关系:

面向字节

面向字符

适配器

InputStream

Reader

InputStreamReader

OutputStream

Writer

OutputStreamWriter

FileInputStream

FileReader

FileOutputStream

FileWriter

StringBufferInputStream

StringReader

StringWriter

ByteArrayInputStream

CharArrayReader

ByteArrayOutputStream

CharArrayWriter

PipedInputStream

PipedReader

PipedOutputStream

PipedWriter

所以刚才写的两段代码就可以这样来通过Reader和Writer来改写:

BufferedInputStream b = new BufferedInputStream(new DataInputStream(new FileInputStream("xxx")));

BufferedReader reader = new BufferedReader(new FileReader("..."));

DataOutputStream d = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("...")));

BufferedWriter writer = new BufferedWriter(new FileWriter("..."));

下面我们来看两种典型的应用方式,以后我们在进行I/O操作是就可以直接使用代码,或者直接套用这样的格式。

应用一:

package typical.usage;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.Arrays;

/**

* @author Administrator 一个读写文件的小工具

*/

public class TextFile extends ArrayList {

private static final long serialVersionUID = 1L;

// 读文件

public static String read(String file) {

StringBuilder builder = new StringBuilder();

try {

BufferedReader bf = new BufferedReader(new FileReader(

new File(file).getAbsoluteFile()));

try {

String s = null;

while ((s = bf.readLine()) != null) {

builder = builder.append(s);

builder.append("\n");

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

bf.close();

} catch (IOException e) {

e.printStackTrace();

}

}

} catch (FileNotFoundException e) {

e.printStackTrace();

}

return builder.toString();

}

// 写文件

public static void write(String file, String content) {

try {

PrintWriter pr = new PrintWriter(new File(file).getAbsoluteFile());

try {

pr.print(content);

} finally {

pr.close();

}

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

// 根据指定的正则表达式拆分文件

public TextFile(String file, String regex) {

super(Arrays.asList(read(file).split(regex)));

if (get(0).equals(""))

remove(0);

}

// 读文件

public TextFile(String file) {

this(file, "\n");

}

// 写文件

public void write(String file) {

try {

PrintWriter pw = new PrintWriter(new File(file).getAbsoluteFile());

try {

for (String item : this) {

pw.print(item);

}

} finally {

pw.close();

}

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

String file = read("D://IAReg.txt");

System.out.println(file);

write("D://b.txt", file);

TextFile tf = new TextFile("D://b.txt");

tf.write("D://c.txt");

TextFile tf2 = new TextFile("D://b.txt", "\\W+");

System.out.println(tf2);

}

}

这个例子展示了读写文件的基本方法,同时还实现了一个文件的过滤器。

应用二:

package typical.usage;

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

/**

*

* @author wangkang

* 打开一个文件用于字符输入,同时为了提高速度运用了缓冲。

*/

public class BufferedInputFile {

public static String read(String fileName) throws IOException {

BufferedReader bf = new BufferedReader(new FileReader(fileName));

String s = null;

StringBuilder bs = new StringBuilder();

while ((s = bf.readLine()) != null) {

bs = bs.append(s + "\n");

}

//关闭文件输入流

bf.close();

return bs.toString();

}

public static void main(String[] args) {

try {

System.out.println(read("D:\\IAReg.txt"));

} catch (IOException e) {

e.printStackTrace();

}

}

}

这个示例展示了利用缓冲打开一个文件,并将其内容防止字符串对象中,当然我们获取了文件内容以后操作是根据我们的实际需求来。

应用三:

package typical.usage;

import java.io.ByteArrayInputStream;

import java.io.DataInputStream;

import java.io.IOException;

public class FormattedMemoryInputStream2 {

public static void main(String[] args) throws IOException {

DataInputStream in = new DataInputStream(new ByteArrayInputStream(

BufferedInputFile.read("D:\\IAReg.txt").getBytes()));

while (in.available() != 0) {

System.out.println(in.readByte());

}

}

}

这个示例展示了格式化的内存输入,new ByteArrayInputStream(

BufferedInputFile.read("D:\\IAReg.txt").getBytes())产生了一个格式化的字节数组共DataInputStream使用。

应用四:

//基本的本件输出

package typical.usage;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintWriter;

import java.io.StringReader;

public class BasicFileOutput {

public static void main(String[] args) throws IOException {

String file = "D:\\test.out";

BufferedReader in = new BufferedReader(new StringReader(

BufferedInputFile.read("D:\\IAReg.txt")));

PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(

file)));

int lineNum = 1;

String s = null;

while ((s = in.readLine()) != null) {

lineNum++;

System.out.println(lineNum + ":" + s);

//将字符串的内容写进文件

out.write(s);

}

in.close();

out.close();

}

}

//文件输出的快捷方式

package typical.usage;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.PrintWriter;

import java.io.StringReader;

public class ShortCutFileOutput {

public static void main(String[] args) throws IOException {

String file = "D:\\test.out";

BufferedReader in = new BufferedReader(new StringReader(

BufferedInputFile.read("D:\\IAReg.txt")));

PrintWriter out = new PrintWriter(file);

int lineNum = 1;

String s = null;

while ((s = in.readLine()) != null) {

lineNum++;

// 将字符串的内容写进文件

out.write(lineNum + ":" + s);

}

in.close();

out.close();

System.out.println(BufferedInputFile.read("D:\\test.out"));

}

}

应用五:

package typical.usage;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public class StoringAndRecoveringData {

public static void main(String[] args) throws IOException {

DataOutputStream out = new DataOutputStream(new BufferedOutputStream(

new FileOutputStream("D://a.java")));

out.writeInt(12345);

out.writeDouble(12345.000);

out.writeUTF("上面的是一个整数和一个浮点数!!");

out.writeChars("上面的是一个整数和一个浮点数!!");

out.close();

DataInputStream in = new DataInputStream(new BufferedInputStream(

new FileInputStream("D://a.java")));

System.out.println(in.readInt());

System.out.println(in.readDouble());

System.out.println(in.readUTF());

System.out.println(in.readChar());

in.close();

}

}

这个示例展示了如何存储和恢复数据。我们在程序中使用DataOutputStream来存储数据,用DataInputStream来读取恢复数据。我们需要知道,只要是DataOutputStream写入的数据都何以利用DataInputStream来准确的得到数据,尽管是在跨平台应用中,这也体现了java的跨平台性。writeUTF()以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流,所以我们可以将字符串和其他数据类型相混合。

应用六:

package typical.usage;

import java.io.IOException;

import java.io.RandomAccessFile;

public class UsingRandomAccessingFile {

static String file = "D://IAReg.txt";

static void play() throws IOException {

RandomAccessFile rf = new RandomAccessFile(file, "r");

for(int i = 0; i < 11; i ++) {

System.out.println(rf.readLine());

}

rf.close();

}

public static void main(String[] args) throws IOException {

//读取数据

play();

RandomAccessFile rf = new RandomAccessFile(file, "rw");

for(int i = 0; i < 3; i ++) {

rf.writeUTF("哈哈哈");

}

rf.close();

//测试修改结果

play();

}

}

这个示例展示了如何读写随机访问文件。我们是通过RandomAccessFile来实现这样的功能的,RandomAccessFile适用于大小已知的记录组成的文件。这个类的构造器的参数需要一个特别的String字符串,用来指定"随机读----r"或者"既读又写-----rw"

到这里就告一段落吧,说的都是一些皮毛的东西,至于一些高级的应用,我也是不太明白。但是只要入门了一切都好说了,面包会有的一切会有的。这一章我们必须要掌握装饰器和适配器模式,这样我们才能理解类之间纷繁复杂的配合使用。

java学习体会论文_Java I/O学习心得一相关推荐

  1. ajax心得体会论文,AJAX重点知识的心得体会

    下面就为大家带来一篇 AJAX重点知识的心得体会.学习还是有点帮助的,给大家做个参考吧. AJAX是什么? 是Asynchronous Javascript And XML的首字母的缩写, 它不是一门 ...

  2. java学习体会论文_关于学习java的心得体会

    关于学习java的心得体会 高中毕业后直接踏入社会的我,开始并不知道java是什么,根本也没有想过会学习这个,甚至于到现在从事这个方面的工作,那么java到底是什呢?Java是一门面向对象编程语言,不 ...

  3. java编程思想 入门_java编程思想学习(基础)

    第一章 java介绍 1.编程的本质: 机器空间:解空间 问题空间:实际需要解决的业务问题,将该问题抽象化,在解空间中对问题建模. 编程就是建立问题空间和机器空间中的关联 面向对象编程思想: 1.万物 ...

  4. java中解决脏读_java并发编程学习之脏读代码示例及处理

    使用interrupt()中断线程     当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即 ...

  5. 尤其是java程序员(转载)_JAVA程序员 学习任务(转载)

    1. 你需要精通面向对象分析与设计(OOA/OOD).涉及模式(GOF,J2EEDP)以及综合模式.你应该了解UML,尤其是class.object.interaction以及statediagram ...

  6. java中线程总结_java中多线程学习笔记总结

    线程的简单学习笔记: 1.进程与线程的概念 进程:从用户角度看进程是应用程序的一个执行过程. 从操作系统核心角度看进程代表的是操作系统分配的内存和CPU时间片等资源的基本单位,是为正在运行的程序提供的 ...

  7. java子类创建过程_JAVA入门小小白学习中ing(匿名对象、封装性、继承性、子类对象的创建过程、spuer关键字(用法一))...

    小小白慢慢学习中ing 第十二天 努力努力 本日内容(匿名对象.封装性.继承性.子类对象的创建过程.spuer关键字) 1.匿名对象 创建对象的语法:Person p1 = new Person(); ...

  8. java后验条件_JAVA并发实战学习笔记——3,4章~

    JAVA并发实战学习笔记 第三章 对象的共享 失效数据: java程序实际运行中会出现①程序执行顺序对打乱:②数据对其它线程不可见--两种情况 上述两种情况导致在缺乏同步的程序中出现失效数据这一现象, ...

  9. java struts2下载文件_java struts2入门学习---文件下载的二种方式

    一.关于文件下载: 文件下载的核心思想即是将文件从一个地方拷贝到另一个地方. 1.传统方式: 在Action中加入大量servlet api 操作.优点是好理解,缺点是耦合度高. 2.stream方式 ...

最新文章

  1. javascript-对混合字母/数字数组进行排序
  2. swoole实现数据库连接池
  3. 周五晚上看了变形金刚
  4. Mybatis入门---一对多、多对多
  5. 监听手指是否离开屏幕android_Flutter事件监听
  6. headfirstjava最新版本下载_读过HeadFirstJava的大神进来看看
  7. 谷歌编码_如何通过学习编码赢得Google之旅
  8. Linux下yum命令详解
  9. 2复数与复变函数(二)
  10. 使Docker Container支持运行SWT程序
  11. IIS中启用ASP并连接Access数据库的解决办法
  12. 常用网络命令:ping命令的使用
  13. 如何解决失眠有效方法,五个助眠小妙招
  14. val_loss先下降后上升或不下降只上升
  15. 固态硬盘:掉盘不识别自检修复,30分钟大法
  16. 给您简单介绍术业进销存管理系统
  17. 随机森林计算特征重要性_随机森林中计算特征重要性的3种方法
  18. 从xss挑战之旅来重读xss(一)
  19. UCOSIII软件定时器
  20. vscode1.65.2 + anaconda 在python拓展为2022.2.1924087327版本上的问题及解决

热门文章

  1. java kettle log_kettle使用log4j管理输出日志
  2. idea中git提交代码更改作者名字(亲测)
  3. 高并发设计方案二(秒杀架构)
  4. 云上如何做冷热数据分离
  5. 为PHP5.4开启Zend OPCode缓存
  6. Go笔试题目Go与PHP分别实现方法
  7. MySQL前缀索引与覆盖索引:前缀索引对于索引精简 覆盖索引对于查询数据索引化
  8. PHP的require与include
  9. 运维工程师是桥的护栏_桥梁专家:钢结构桥比混凝土桥易涡振 以后出现涡振可能性会提高...
  10. a7100换电池_动动手你也行 篇十四:冲动是魔鬼——单反电池换芯失败记