Java教程

JAVA IO相关类的介绍

本文主要是介绍JAVA IO相关类的介绍,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

File类

如果希望在程序中操作文件和目录,都可以通过File完成,其能新建、删除、重命名文件和目录,但是不能访问文件内容。

https://www.runoob.com/java/java-file.html

文件过滤器FilenameFilter

File类中的list()方法可以接受一个FilenameFilter参数,通过该参数可以只列出符合条件的文件。

FilenameFilter接口包含一个accept(File dir,String name)方法,该方法一次对指定File的所有子目录或文件进行迭代,如果该方法返回true,list()方法会列出该子目录或文件。

//用的lambda表达式new的FilenameFilter
File file = new File(".");
String[] nameList = file.list( (dir,name) -> name.endsWith(".java")||name.endsWith(".iml") || new File(name).isDirectory()  );
for(String name : nameList){
    System.out.println(name);
}

上面用Lambda表达式实现了FilenameFilter接口,该接口内只有一个抽象方法accept(),是一个函数式接口;等同于如下代码:

static class filter implements FilenameFilter{
    @Override
    public boolean accept(File dir, String name) {
        if(name.endsWith(".java")||name.endsWith(".iml") || new File(name).isDirectory()){
            return true;
        }
        return false;
    }
}

    public static void main(String args[]) {

        File file = new File(".");
        System.out.println(file.getAbsolutePath());

        filter f = new filter();
        String[] nameList = file.list(f);
        for(String name : nameList){
            System.out.println(name);
        }

    }

Java的IO流

所有的IO流设计的类都是从InputStream和OutputStream,Reader和Writer这几个类派生的;JAVA的流能分为以下几种:

输入流和输出流

输入流:只能从中读取数据,不能向里面写;

输出流:只能向里面写数据,不能从里面读;

字节流和字符流

用法几乎一样,区别在于字节流操作的数据单元是8位的字节,字符流是16位的字符;

字节流主要由InputStream和OutputStream作为基类,字符流主要由Reader和Writer作为基类;

节点流和处理流

从/向一个特定的IO设备进行读/写的流,称为节点流,节点流也被称为低级流;

处理流用于对一个已存在的流进行封装,通过封装后的流实现数据读/写功能。也被称为高级流;

使用处理流时,程序并不会直接连接到实际的数据源,使用数据流,程序可以使用完全相同的输入输出代码访问不同数据源。

字节流和字符流

InputStream和Reader

int read();读取单个字节;

int read(byte[] b);读取最多b.length个字节的数据,并将其存储在字节数组b中;

int read(byte[] b,int off,int len)读取最多len个字节的数据,并将其存储在字节数组b中,从off位置开始放;

void mark(int readAheadLimit)在记录指针当前位置放一个标记

boolean markSupported();判断该输入流是否支持mark()操作

void reset();记录指针定位到上次mark位置

long skip(long n);记录指针向前移动n个字节/字符

OutputStream和Writer

类似,就把read换成write,用法相反,前面是读,这里是写

输入/输出流体系

处理流

一般使用处理流来包装结点流,程序通过处理流来执行输入输出,让节点流与底层IO设备和文件交互。

只要一个流的构造参数不是物理节点而是已经存在的流,那么这个流就一定是处理流。

FileOutputStream fos = new FileOutputStream("a.txt");
PrintStream printStream = new PrintStream(fos);

转换流

转换流(InputStreamReader和OutputStreamReader)用于实现将字节流转换成字符流,

InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(reader);

String line = null;
while ((line=br.readLine())!=null){
    if(line.equals("00")){
        System.exit(1);
    }
    else {
        System.out.println(line);
    }

推回输入流

PushbackInputStream和PushbackReader

void read(int buf);把一个字节或字符内容退回缓冲区,从而允许重复读取刚刚读取的内容;

void read(byte[]/char[] b);把一个字节或字符数组的内容退回缓冲区,从而允许重复读取刚刚读取的内容;

void read(byte[]/char[] b,int off,int len),把一个字节或字符数组中,从off开始长度为len的字符的内容退回缓冲区,从而允许重复读取刚刚读取的内容;

重定向标准输入/输出

JAVA标准输入输出分别通过System.in和System.out代表键盘和显示器,System提供三个方法重定向输入输出,(重定向后,System.out.print从原本的键盘和显示器读写,变成了你指定的文件或其他东西)

setErr(PrintStream)重定向错误输出流

setIn(InputStream)重定向输入流

setOut(PrintStream)重定向输出流

        PrintStream printStream = new PrintStream("a.txt");
        System.setOut(printStream);
        System.out.println("输出一个字符串");

JAVA虚拟机读取其他进程的数据

使用Runtime对象的exec()对象可运行平台上其他程序,该方法返回一个Process对象,代表该JAVA程序启动的子进程,可通过Process对象让程序和子进程进行通信;

InputStream getErrorStream();获取子进程的错误流;

InputStream getInputStream();获取子进程的输入流;

OutputStream getOutputStream();获取子进程的输出流;

Process p = Runtime.getRuntime().exec("javac");
try(
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))
)
{
    String buff =null;
    while ((buff = br.readLine())!=null){
        System.out.println(buff);
    }
}

RandomAccessFile

该类提供了众多方法来访问文件内容,可以随机读取文件内容,也可以向文件输出数据(特点在于可以直接跳转到文件的任意地方读写数据);

但是它只能读写文件,不能读写其他IO节点;

通过以下两个方法操纵指针:

long getFilePointer();返回文件记录指针的当前位置;

void seek( long pos );把文件记录指针定位到当前位置;

同时RandomAccessFile也能使用三个read和三个write方法;

NIO

上面传统的输入输出流都可能会阻塞线程,而且都是通过字节的移动来处理的,也就是说,面向流的输入输出都是系统一次只能处理一个字节,效率不高,从JDK1.4开始,JAVA提供了一系列改进的输入输出新功能,被放在java.nio包下;

NIO和传统IO都用于进行输入输出,但是NIO采用内存映射文件的方式来处理输入输出,NIO将文件或文件的一段区域隐射到内存之中,由此可以向访问内存一样去访问文件;

JAVA中NIO相关的包如下:

java.nio;主要包含各种与Buffer相关的类

java.nio.channels;主要包含与Channel和Selector相关的类

java.nio.charest;主要包含与字符集相关的类

java.nio.channels.spi;主要包含与Channels相关的服务提供者编程接口

java.nio.charest.spi;包含与字符集相关的服务提供者编程接口

Channel(通道)和Buffer(缓冲)是NIO中的两个核心对象,Channel是对传统的输入输出系统的模拟,新IO系统中所有数据都要通过通道传输;Channel与系统的InputStream、OutputStream最大区别在于它提供了一个map()方法,通过该方法可以直接把一块数据映射到内存中。

Buffer类似一个容器,它的本质是一个数组,发送到Channel中的所有对象都必须先放到Buffer中,而从Channel读取的数据也要先放到Buffer中。

Charest类:用于将Unicode字符创映射成字节序列以及逆映射

Selector类:用于支持非阻塞式输入输出;

Buffer

一般用下面函数得到一个Buffer对象:

static XXXBuffer allocate(int capacity);创建一个容量为capacity的XXbuffer对象;

Buffer有三个重要概念:

capacity - 缓冲区大小,缓冲区一旦创建出来以后,这个属性就不会再变化了。
position - 读写数据的定位指针,用来指明下一个可以被读写的缓冲区位置索引。
limit - 读写的边界,第一个不应该被读出或写入的缓冲区位置索引。位于其后的数据不能被读或写。

同时Buffer也支持mark;

Buffer主要作用就是装数据,,开始时position为0,limit为capacity,当往里面通过put()填数据的时候,position相应的向后移,装入数据结束后,调用filp()方法,该方法将limit设置为position所在位置,position设置为0;输出数据结束后,调用clear()方法,不清空数据,只是将position设为0;limit设为capacity;

一般用put()和get()来访问数据

CharBuffer charBuffer = CharBuffer.allocate(8);
charBuffer.put('a');
charBuffer.put('c');
charBuffer.put('b');
System.out.println(charBuffer.get());
charBuffer.flip();
System.out.println(charBuffer.get(0));
charBuffer.clear();
System.out.println(charBuffer.get(0));

Channel

Channel类似于传统的流对象,但有两个区别:

Channel可直接将指定文件的部分或全部直接映射成Buffer。

程序不能直接访问Channel中的数据,Channel只能与Buffer进行交互。

Channel分很多种,Pipe.SinkChannel、Pipe.SourceChannel是用于支持线程通信的管道Channel,SeverSockerChannel、SocketChannel是用于支持TCP通信的Channel等,本节主要使用FileChannel;

所有的Channel都不应该使用构造器直接创建,而是通过传统的节点InputStream、OutputStream的geChannel()方法获得;

Channel最常用的方法有:

map():用于将Channel对应的数据映射成ByteBuffer;

read()和write()由一系列重载,用于读写数据;

File f = new File("D:\\JAVA_Project\\a1\\src\\IO\\NIO.java");

FileChannel inc = new FileInputStream(f).getChannel();
FileChannel outc = new FileOutputStream("channel.txt").getChannel();

MappedByteBuffer buffer = inc.map(FileChannel.MapMode.READ_ONLY,0,f.length());
//使用GBK字符集创建解码器
Charset charset = Charset.forName("GBK");

outc.write(buffer);
buffer.clear();
//使用解码器将ByteBuffer转换成CharBuffer
CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
CharBuffer charBuffer =decoder.decode(buffer);

System.out.println(charBuffer);

字符集和Charset

JAVA默认使用Unicode字符集,但很多操作系统不实用Unicode字符集,则从系统中读取数据到JAVA程序中时可能乱码;

Charest用于处理字节序列和字符序列直接的转换关系;

可通过如下方式获得Charest对象

Charset charset = Charset.forName("GBK");
Charset charset1 = Charset.forName("UTF-8");

然后获得编码解码对象:

CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
CharsetEncoder encoder = Charset.defaultCharset().newEncoder();

之后通过encode()和decode()方法转换;

文件锁

可以使用FileLock防止多个程序并发操作同一个文件

lock():试图锁定某个文件时,如果无法得到锁,会堵塞下去;

tryLock():尝试锁定文件,得到就会返回文件锁,否则返回Null;

JAVA7的NIO.2

JAVA7对NIO进行的改进

Path、Paths和File核心API

早期的File类功能有限,性能也不高,大多数方法出错时也不会提供异常信息

NIO.2引入的Path接口,代表一个平台无关的平台路径,此外NIO.2还提供了Files(提供大量静态的操作文件的方法)、Paths(包含两个返回Path的静态工厂方法)两个工具类;

https://www.cnblogs.com/codderYouzg/p/12418878.html

使用FileVisitor遍历文件和目录

File提供下面两个方法遍历文件和子目录

WalkFileTree(Path start,FileVisitor<? super Path > visitor);遍历start路径下的所有文件和子目录;

WalkFileTree(Path start,Set< FileVisitOption >options,int maxDepth ,FileVisitor<? super Path > visitor);类似,最多遍历maxDepth深度的文件;

两个方法都需要FileVisitor参数,可通过重写下面四个方法自定义FileVisitor

  • postVisitDirectory(T dir, IOException exc) 在一个目录被处理后触发
  • preVisitDirectory(T dir, BasicFileAttributes attrs) 在一个目录被处理前触发
  • visitFile(T file, BasicFileAttributes attrs) 在遇到一个文件或目录时触发
  • visitFileFailed(T file, IOException exc) 在试图访问文件或目录,发生错误时触发。例如:没有权限打开目录;

FileVisitResult主要包含四个常见的操作。

FileVisitResult.CONTINUE 继续遍历
FileVisitResult.TERMINATE 中止访问
FileVisitResult.SKIP_SIBLINGS 不访问同级的文件或目录
FileVisitResult.SKIP_SUBTREE 不访问子目录

WatchService监控文件变化

访问文件属性

FileAttributeView:代表某种文件属性的“视图”;

FileAttributes:代表某种文件属性的“集合”,一般通过FileAttributeView获取

这篇关于JAVA IO相关类的介绍的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!