IO

文件
ava 使用 File 类来直接处理文件和文件系统。File 类没有指定信息怎样从文件读取或向文件存储;它描述了文件本身的属性。File 对象用来获取或处理与磁盘文件相关的信息,例如权限,时间,日期和目录路径。此外,File 还浏览子目录层次结构。Java 中的目录当成 File 对待,它具有附加的属性——一个可以被 list() 方法检测的文件名列表。
构造方法
File 类提供了以下构造方法:

//根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
File(File parent, String child)

//通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例
File(String pathname)

// 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例
File(String parent, String child)

//通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例
File(URI uri)

使用示例

//一个目录路径参数
File f1 = new File("/home/project/");

//对象有两个参数——路径和文件名
File f2 = new File("/home/project/","a.bat");

//指向f1文件的路径及文件名
File f3 = new File(f1,"a.bat");

常用方法请查看java API文档。
java.io 包中提供了文件操作类:

1.用于读写本地文件系统中的文件:FileInputStream 和 FileOutputStream
2.描述本地文件系统中的文件或目录:File、FileDescriptor 和 FilenameFilter
3.提供对本地文件系统中文件的随机访问支持:RandomAccessFile
文件流的构造方法:

//打开一个以 f 描述的文件作为输入
FileInputStream(File f)

//打开一个文件路径名为 name 的文件作为输入
FileInputStream(String name)

//创建一个以 f 描述的文件作为输出
//如果文件存在,则其内容被清空
FileOutputStream(File f)

//创建一个文件路径名为 name 的文件作为输出
//文件如果已经存在,则其内容被清空
FileOutputStream(String name)

//创建一个文件路径名为 name 的文件作为输出
//文件如果已经存在,则在该输出上输出的内容被接到原有内容之后
FileOutputStream(String name, boolean append)

代码示例:

File f1 = new File("file1.txt");
File f2 = new File("file2.txt");
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);

如果文件内容保存的是字符信息,如 txt 文件等,还可以使用 FileReader 来读取文件内容。

FileReader file = new FileReader("/home/project/shiyanlou.txt");
//声明一个文件输入流file,并指明该文件在系统中的路径以方便定位

int data = 0;
//声明一个整型变量用于存放读取的数据

while((data=file.read())!=-1){
    //在while循环中使用read()方法持续读取file,数据赋到data中
    //如果读取失败或者结束,则将返回-1,这个特殊的返回值可以作为读取结束的标识

    System.out.print((char)data);
    //输出读取到数据
}

file.close();
//一定要记得读取结束后要关闭文件

随机读写
对于 FileInputStream/FileOutputStream、FileReader/FileWriter 来说,它们的实例都是顺序访问流,即只能进行顺序读 / 写。而类 RandomAccessFile 则允许文件内容同时完成读和写操作,它直接继承 Object,并且同时实现了接口 DataInput 和 DataOutput。

随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取 / 写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。

RandomAccessFile 提供了支持随机文件操作的方法:

readXXX() 或者 writeXXX():readInt(), readLine(), writeChar(), writeDouble() 等。
int skipBytes(int n): 将指针向下移动若干字节。
int length(): 返回文件长度。
long getFilePointer(): 返回指针当前位置。
void seek(long pos): 将指针调用所需位置。

mode 的取值:

r: 只读,任何写操作都讲抛出 IOException
rw: 读写,文件不存在时会创建该文件,文件存在是,原文件内容不变,通过写操作改变文件内容。
rws: 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
rwd: 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。

文件操作
在平时编写程序的时候,经常会对文件进行操作,比如文件的赋值,重命名,删除等。接下来学习使用 Java 操作文件。
可以使用 Files 工具类的 copy(Path source,Path target,CopyOption… options) 拷贝文件或者目录。如果目标文件存在,那么赋值将失败,除非我们在 options 中指定了 REPLACE_EXISTING 属性。当该命令复制目录时,如果目录中已经有了文件,目录中的文件将不会被复制。CopyOption 参数支持以下 StandardCopyOption 和 LinkOption 枚举:

  • REPLACE_EXISTING:即使目标文件已存在,也执行复制。如果目标是符号链接,则复制链接本身(而不是链接的目标)。如果目标是非空目录,则复制将失败并显示 FileAlreadyExistsException 异常。
  • COPY_ATTRIBUTES:将与文件关联的文件属性复制到目标文件。支持的确切 - 文件属性是文件系统和平台相关的,但 last-modified-time 跨平台支持并复制到目标文件。

NOFOLLOW_LINKS:表示不应遵循符号链接。如果要复制的文件是符号链接,则复制链接(而不是链接的目标)
移动和重命名
Files 类的 move(Path, Path, CopyOption… options) 方法移动文件或者目录,同样目标目录存在,那么比如使用REPLACE_EXISTING。 options 参数支持 StandardCopyOption 的以下枚举:

  • REPLACE_EXISTING:即使目标文件已存在,也执行移动。如果目标是符号链接,则替换符号链接,但它指向的内容不受影响。
  • ATOMIC_MOVE:将移动作为原子文件操作执行。如果文件系统不支持原子移动,则抛出异常。使用,ATOMIC_MOVE 您可以将文件移动到目录中,并保证观察目录的任何进程都可以访问完整的文件。

move 方法除了可以移动之外,也可以用与重命名。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class MoveDemo {
    public static void main(String[] args) {
        try {
            //将1.txt 重命名为3.txt 如果只需要移动到不同的目录,文件名不变即可
            Files.move(Paths.get("/home/project/1.txt"), Paths.get("/home/project/3.txt"), StandardCopyOption.REPLACE_EXISTING);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

运行:

renameTo移动结果:true

目录读取

Java 中读取目录中的文件可以直接使用 listFiles() 方法读取,但是也只能读取当前目录中的文件,如果当前目录中还有二级目录如何解决呢?三级目录呢?接下来将使用 Java 读取当前目录和子目录中的所有文件。

import java.io.File;
public class ReadDir {
    public static void main(String[] args) {
        readDir(new File("/home"));
    }

    static void readDir(File file) {
        if (file == null) {
            return;
        }
        //如果当前file是目录
        if (file.isDirectory()) {
            File[] files;
            //如果目录不为空
            if ((files = file.listFiles()) != null) {
                for (File file1 : files) {
                    //递归读取目录内容
                    readDir(file1);
                }
            }
        } else {
            //如果不是目录 直接输出文件名
            System.out.println(file.getName());
        }
    }
}

IO 流
在大多数程序中,都需要对输入输出进行处理。例如我们中需要获取用户从键盘上的输入,需要在控制台输出结果等等。除此之外还有从文件中读取数据,向文件中写入数据等等。在 Java 中,我们把这些不同类型的输入输出源抽象地称为 流,也就是 Stream;在里面输入输出的数据则称为数据流(Data Stream),它们通常具有统一的接口。
于是我们得到了数据流的定义:

一个 Java I/O 对象叫做数据流。读取数据到内存的对象叫做输入流,内存写出数据的对象叫做输出流。

针对其面向的不同角度,我们大致可以将流分为下面几种类型:

  • 按照数据流的方向不同分为 输入流 和 输出流。这种分类不是绝对的,例如在向一个文件写入数据时,它就是输出流;而在读取数据时,它就是输入流。

  • 按照处理数据的单位不同分为 字节流 和 字符流

  • 按照功能的不同分为 节点流 和 处理流
    字节流
    字节流主要操作 byte 类型数据,以 byte 数组为准,java 中每一种字节流的基本功能依赖于基本类 InputStream 和 Outputstream,他们是抽象类,不能直接使用。字节流能处理所有类型的数据(如图片、avi 等)。
    InputStream
    InputStream 是所有表示字节输入流的父类,继承它的子类要重新定义其中所定义的抽象方法。InputStream 是从装置来源地读取数据的抽象表示,例如 System 中的标准输入流 in 对象就是一个 InputStream 类型的实例。
    InputStream 类方法:
    在 InputStream 类中,方法 read() 提供了三种从流中读数据的方法:

  • int read():从输入流中读一个字节,形成一个 0~255 之间的整数返回(是一个抽象方法)

  • int read(byte b[]):从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

  • int read(byte b[],int off,int len):从输入流中读取长度为 len 的数据,写入数组 b 中从索引 off 开始的位置,并返回读取得字节数。
    对于这三个方法,若返回 -1,表明流结束,否则,返回实际读取的字符数。
    OutputStream
    OutputStream 是所有表示位输出流的类之父类。子类要重新定义其中所定义的抽象方法,OutputStream 是用于将数据写入目的地的抽象表示。例如 System 中的标准输出流对象 out 其类型是 java.io.PrintStream,这个类是 OutputStream 的子类。
    字符流

字符流以字符为单位,根据码表映射字符,一次可能读多个字节,只能处理字符类型的数据。
java.io 包中专门用于字符流处理的类,是以 Reader 和 Writer 为基础派生的一系列类。

同类 InputStream 和 OutputStream 一样,Reader 和 Writer 也是抽象类,只提供了一系列用于字符流处理的接口。它们的方法与类 InputStream 和 OutputStream 类似,只不过其中的参数换成字符或字符数组。

Reader 是所有的输入字符流的父类,它是一个抽象类。
转换流
InputStreamReader 和 OutputStreamWriter 是 java.io 包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介:从字节输入流读入字节,并按编码规范转换为字符;往字节输出流写字符时先将字符按编码规范转换为字节。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范,以便把以字节方式表示的流转换为特定平台上的字符表示。

InputStreamReader(InputStream in); //缺省规范说明

//指定规范 enc
InputStreamReader(InputStream in, String enc);

OutputStreamWriter(OutputStream out); //缺省规范说明

//指定规范 enc
OutputStreamWriter(OutputStream out, String enc);

BufferedReader 和 BufferedWrite

  • public String readLine():BufferedReader 的方法,从输入流中读取一行字符,行结束标志 \n、\r 或者两者一起(这是根据系统而定的)
  • public void newLine():BufferedWriter 的方法,向输出流中写入一个行结束标志,它不是简单地换行符 \n 或\r,而是系统定义的行隔离标志(line separator)。

NIO
Java NIO(New IO) 发布于 JDK1.4,用于代替 Java 标准 IO 。Java NIO 是面向缓存的、非阻塞的 IO,而标准 IO 是面向流的,阻塞的 IO。

首先理解 NIO 的重要概念:Buffer(缓冲区)

  • NIO 读取或者写入数据都要通过 Buffer
  • 通过 allocate() 方法分配 Buffer,Buffer 不可实例化,Buffer 是抽象类,需要使用具体的子类,比如 ByteBuffer。
  • Buffer 的参数
  • capacity :缓冲区的容量
  • position :当前指针位置,没读取一次缓冲区数据或者写入缓冲区一个数据那么指针将会后移一位
  • limit :限制指针的移动,指针不能读取 limit 之后的位置
  • mark :如果设置该值,那么指针将移动到 0 - position 的位置
  • 最后可以这几个参数的关系如下:mark <= position <= limit <= capacity
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值