Java IO-(第六天)

Java IO-(第六天)

一、IO简介

IO是指Input/Output,即输入与输出
Input从外部读入数据到内存,读文件,从网络读取等
Output从内存输出到外部,写文件,输出到网络等
IO流是一种顺序读写数据的模式,单向流动,以byte为最小单位(字节流)
如果字符不是单个自己表示的ASCII码,字符流传输的最小数据单位是char
字符流输出的byte取决于编码方式。(ASCII码,UTF-8,Unicode)
Bytes和String字符串之间相互转换

 //Original String
        String string = "hello world";
         
        //Convert to byte[]
        byte[] bytes = string.getBytes();
         
        //Convert back to String
        String s = new String(bytes);
         
        //Check converted string against original String
        System.out.println("Decoded String : " + s);

二、同步和异步IO

同步IO:读写IO时代码等待数据返回后才继续执行后续代码,代码编写简单,CPU执行效率低。
异步IO:读写IO时仅发出请求,然后立刻执行后续代码,代码编写复杂,CPU执行效率高。

JDK提供的JAVA.IO是同步IO
JDK提供的JAVA.NIO是异步IO

JAVA.IO

抽象类 InputStream OutputStream Reader Writer
实现类 FileInputStream FileOutputStream FileReader FileWriter

三、File类

java.io.File表示文件系统的一个文件或目录

File f = new File(String pathName)//可以是相对路径和绝对路径
//windows
String path1 = "c:\\windows\\test.txt";
//linux
String path2 = "/usr/bin/java.txt";

获取路径的方法

f.getPath();
f.getAbsolutePath();//绝对路径
f.getCanonicalPath();

判断文件对象是文件还是目录

f.isFile();//是否为文件
f.isDirectory();//是否为目录

用File对象获取到一个文件时,还可以进一步判断文件的权限和大小:

boolean canRead():是否可读;
boolean canWrite():是否可写;
boolean canExecute():是否可执行;
long length():文件字节大小。

通过createNewFile()创建一个新文件,用delete()删除该文件,File对象提供了createTempFile()来创建一个临时文件,以及deleteOnExit()在JVM退出时自动删除该文件。

使用list()和listFiles()列出目录下的文件和子目录名。当File对象表示一个目录时,可以使用list()和listFiles()列出目录下的文件和子目录名。listFiles()提供了一系列重载方法,可以过滤不想要的文件和目录。

扫描二维码关注公众号,回复: 10691936 查看本文章
 File[] fs2 = f.listFiles(new FilenameFilter() { // 仅列出.exe文件
            public boolean accept(File dir, String name) {
                return name.endsWith(".exe"); // 返回true表示接受该文件
            }
        });

和文件操作类似,File对象如果表示一个目录,可以通过以下方法创建和删除目录:

boolean mkdir():创建当前File对象表示的目录;
boolean mkdirs():创建当前File对象表示的目录,并在必要时将不存在的父目录也创建出来;
boolean delete():删除当前File对象表示的目录,当前目录必须为空才能删除成功。

四、InputStream类

java.io.InputStream是所有输入流的超类。
abstract int read() 读取下一个字节,并返回字节数(0-255);如果已读到末尾,返回-1。
int read(byte[] b)读取若干字节,并填充到byte[]数组,返回读取的字节数。
int read(byte[] b,int off,int len)指定byte[]数组的偏移量和最大填充数。
void close()关闭输入流

try{}catch(Exception e){}保证输入流的正常关闭

public void readFile() throws IOException {
    try (InputStream input = new FileInputStream("src/readme.txt")) {
        // 定义1000个字节大小的缓冲区:
        byte[] buffer = new byte[1000];
        int n;
        while ((n = input.read(buffer)) != -1) { // 读取到缓冲区
            System.out.println("read " + n + " bytes.");
        }
    }
}

read()是一个阻塞blocking的方法,需要等待读取结束

五、OutputStram类

java.io.OutputStream是所有输出流的超类。
abstract write(int b)写入一个字节
void write(byte[] b)写入byte[]数组的所有字节
void write(byte[] b,int off,int len)写入byte[]数组指定范围的字节
void close()关闭输出流
void flush()将缓冲区的内容输出

try{}finally{}保证输入流的正常关闭

public void writeFile() throws IOException {
    OutputStream output = new FileOutputStream("out/readme.txt");
    output.write("Hello".getBytes("UTF-8")); // Hello
    output.close();
}

OutputStream的write()方法也是阻塞的

六、Filter模式

JDK提供InputStream包括:
FileInputStream从文件读取数据
ServletInputStream从HTTP请求读取数据
Socket.getInputStream()从TCP连接读取数据

如果我们要给FileInputStream添加缓冲功能,则可以从FileInputStream派生一个类:

BufferedFileInputStream extends FileInputStream
如果要给FileInputStream添加计算签名的功能,类似的,也可以从FileInputStream派生一个类:

DigestFileInputStream extends FileInputStream
如果要给FileInputStream添加加密/解密功能,还是可以从FileInputStream派生一个类:

CipherFileInputStream extends FileInputStream
如果要给FileInputStream添加缓冲和签名的功能,那么我们还需要派生BufferedDigestFileInputStream。如果要给FileInputStream添加缓冲和加解密的功能,则需要派生BufferedCipherFileInputStream。

InputStream input = new GZIPInputStream(
	new BufferInputStream(
		new FileInputStream("String pathName")
));

通过组合功能而非继承的设计模式称为Filter模式(或Decorator模式)

七、Zip

ZipInputStream是一种FilterInputStream,可以直接读取Zip内容。
读取zip包

try (ZipInputStream zip = new ZipInputStream(new FileInputStream(...))) {
    ZipEntry entry = null;
    while ((entry = zip.getNextEntry()) != null) {
        String name = entry.getName();
        if (!entry.isDirectory()) {
            int n;
            while ((n = zip.read()) != -1) {
                ...
            }
        }
    }
}

写入zip包

try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(...))) {
    File[] files = ...
    for (File file : files) {
        zip.putNextEntry(new ZipEntry(file.getName()));
        zip.write(getFileDataAsBytes(file));
        zip.closeEntry();
    }
}

八、读取classpath文件

从classpath读取文件可以避免不同环境下文件路径不一致的问题。
如果我们把default.properties文件放到classpath中,就不用关心它的实际存放路径。

在classpath中的资源文件,路径总是以/开头,我们先获取当前的Class对象,然后调用getResourceAsStream()就可以直接从classpath读取任意的资源文件。

try (InputStream input = getClass().getResourceAsStream("/default.properties")) {
    // TODO:
}

九、序列化和反序列化

序列化是指把一个java对象变成二进制内容(byte[])

  • 序列化后可以把byte[]保存到文件中
  • 序列化后可以把byte[]通过网络传输
    必须实现Serializable接口。此接口没有定义任何方法,空接口被称为标记接口(Marker Interface)

反序列化是指把一个二进制内容(也就是byte[]数组)变回Java对象。

  • 到文件中的byte[]数组又可以“变回”Java对象
  • 从网络上读取byte[]并把它“变回”Java对象。

ObjectInputStream 从二进制流读取一个java对象
ObjectOutputStream 把一个java对象写入二进制流

反序列化由JVM直接构造出Java对象,不调用构造方法

java的序列化机制仅仅适用于java,如果需要与其他语言交换数据,必须使用通用的序列化方法,例如:JSON

十、Reader

InputStream Reader
字节流,以byte为单位 字符流,以char为单位
读取字节(-1,0~255):int read() 读取字符(-1,0~65535):int read()
读到字节数组:int read(byte[] b) 读到字符数组:int read(char[] c)

java.io.Reader是所有字符输入流的超类,它最主要的方法是:

public int read() throws IOException;

int read(char[] c) 读取若干字符并填充到char[]数组,返回读取的字符数。
int read(char[] c,int off,int len) 指定char[]数组的偏移量和最大填充数。
void close() 关闭reader

try{}finally{}保证输入流的正常关闭

public void readFile() throws IOException {
    try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) {
        char[] buffer = new char[1000];
        int n;
        while ((n = reader.read(buffer)) != -1) {
            System.out.println("read " + n + " chars.");
        }
    }
}
try (Reader reader = new InputStreamReader(new FileInputStream("src/readme.txt"), "UTF-8")) {
    // TODO:
}

十一、Writer

Reader是带编码转换器的InputStream,它把byte转换为char,而Writer就是带编码转换器的OutputStream,它把char转换为byte并输出。

Writer和OutputStream的区别如下:

OutputStream Writer
字节流,以byte为单位 字符流,以char为单位
写入字节(0~255):void write(int b) 写入字符(0~65535):void write(int c)
写入字节数组:void write(byte[] b) 写入字符数组:void write(char[] c)
无对应方法 写入String:void write(String s)

Writer是所有字符输出流的超类,它提供的方法主要有:

写入一个字符(0~65535):void write(int c);
写入字符数组的所有字符:void write(char[] c);
写入String表示的所有字符:void write(String s)。

try (Writer writer = new FileWriter("readme.txt", StandardCharsets.UTF_8)) {
    writer.write('H'); // 写入单个字符
    writer.write("Hello".toCharArray()); // 写入char[]
    writer.write("Hello"); // 写入String
}
try (Writer writer = new OutputStreamWriter(new FileOutputStream("readme.txt"), "UTF-8")) {
    // TODO:
}

十二、printStream和printWriter

printStream

System.out.print(12345); // 输出12345
System.out.print(new Object()); // 输出类似java.lang.Object@3c7a835a
System.out.println("Hello"); // 输出Hello并换行

printWriter

 StringWriter buffer = new StringWriter();
        try (PrintWriter pw = new PrintWriter(buffer)) {
            pw.println("Hello");
            pw.println(12345);
            pw.println(true);
        }
        System.out.println(buffer.toString());
发布了44 篇原创文章 · 获赞 0 · 访问量 1414

猜你喜欢

转载自blog.csdn.net/weixin_44872254/article/details/104856507