文件操作和IO流

    技术2023-06-30  81

    第一章 文件操作File

    文件操作的概念

    File是 java.io 包中的一个类。 是对磁盘上的某一个文件、文件夹(目录)的描述。 所谓的文件操作,其实都是需要使用这个类来完成的。

    File类常用的构造方法

    参数介绍String pathname传递一个文件/文件夹的路径String parent, String child将parent和child拼接后作为文件/文件夹的路径File parent, String child将parent所描述的文件和child拼接后作为文件/者文件夹的路径

    File类常用方法

    返回值方法名介绍booleanexist()文件/文件夹是否存在booleanisFile()是否是一个文件booleanisDirectory()是否是一个目录intlength()得到文件的大小(只能获取文件的大小)booleanisHidden()是否隐藏booleancanRead()是否可读booleancanWrite()是否可写booleancanExecute()是否可执行StringgetName()获取文件名StringgetPath()获取文件的相对路径StringgetAbsolutePath()获取文件的绝对路径StringgetParent()获取父目录路径FilegetParentFile()获取父目录File对象longlastModifified()最后修改时间

    代码练习

    package com.qf.io; import java.io.File; import java.io.FileFilter; import java.io.IOException; /** * File类型的构造器的学习 */ public class FileTest { public static void main(String[] args) throws IOException { // test1(); // File dir1 = new File("dir1"); // delAll(dir1); // dir1.delete(); delDir("dir1"); } /** * 练习: 在项目下创建一个文件夹dir1,在文件夹里创建两个文件file1,file2 * 然后再创建一个子目录dir2 ,dir2有一个文件file3 * 然后单独写一个方法delDir(String pathname )用于删除指定目录。比如dir1 */ public static void delDir(String pathname){ //使用File来描述给定的路径 File file = new File(pathname); if(!file.exists()){ return; } if(file.isFile()){ file.delete(); return; } if(file.isDirectory()){ //获取目录里的子文件(文件夹),可能是空 File[] files = file.listFiles(); for (File file1 : files) { delDir(file1.getPath()); } file.delete(); } } /** * 在项目下创建文件和文件夹的演示。 */ public static void test1(){ try { File file1 = new File("a.txt"); if(!file1.exists()){ file1.createNewFile(); } File file2 = new File("dir1"); if(!file2.exists()){ file2.mkdir(); } File file3 = new File("dir1/file1"); if(!file3.exists()){ file3.createNewFile(); } }catch (IOException e) { e.printStackTrace(); } } /** * 列出目录里的内容的方法 */ public static void methodUsage3(){ //描述的是一个目录 File file1 = new File("D:/io/a"); File[] files = file1.listFiles(); //此方法返回的是描述目录下的所有子内容(文件/文件夹),每一个子内容都被封装成了File对象, for (File file : files) { System.out.println(file.getAbsolutePath()); } System.out.println("---------------------------"); String[] strings = file1.list(); //返回指定目录下的所有的子内容的名称数组 for (String string : strings) { System.out.println(string); } System.out.println("------------过滤器-----------------"); //使用FileFilter过滤器筛选出.txt结尾的文件 File[] files1 = file1.listFiles(pathname -> !pathname.getName().endsWith(".txt")); for (File file : files1) { System.out.println(file.getName()); } } /** * 文件/文件夹的创建,删除,重命名等方法 * @throws IOException */ public static void methodUsage2() throws IOException { //描述一个文件夹:D:/io/a File file1 = new File("D:/io/a"); if (!file1.exists()){ file1.mkdir(); //用于创建文件夹的方法 } //描述一个文件夹: D:/io/b/c/d/ File file2 = new File("D:/io/b/c/d"); if(!file2.exists()){ file2.mkdirs(); //用于创建多层级目录 System.out.println("--------"); } File file3 = new File("D:/io/a"); boolean flag = file3.mkdir(); System.out.println("是否创建成功:"+flag); //描述一个文件 D:/io/a/1.txt File file4 = new File("D:/io/a/1.txt"); if(!file4.exists()){ flag = file4.createNewFile(); //此方法用于创建文件 System.out.println("创建是否成功:"+flag); } //将file4描述的文件更名为2.txt File file5 = new File("D:/io/a/2.txt"); flag = file4.renameTo(file5); System.out.println("重命名成功?"+flag); //先创建一个文件D:/io/a/3.txt 然后删除 File file6 = new File("D:/io/a/3.txt"); if(!file6.exists()){ file6.createNewFile(); } if(file6.exists()){ flag = file6.delete(); //delete方法用于删除文件。 System.out.println("是否删除成功:"+flag); } //删除D:io/a目录 注意:delete方法删除目录时,此目录必须是空的。 File file7 = new File("D:/io/a"); if(file7.exists()){ flag = file7.delete(); System.out.println("删除成功?"+flag); } //删除D:/io/b/c/d d目录是空的 File file8 = new File("D:/io/b/c/d"); if(file8.exists()){ flag = file8.delete(); System.out.println("删除成功?"+flag); } } /** * 常用的相关属性信息的方法 */ public static void methodUsage1(){ /** * */ File file1 = new File("D:/io/test1.txt"); System.out.println("文件是否存在:"+file1.exists()); System.out.println("是否是一个文件:"+file1.isFile()); System.out.println("是否是一个目录(文件夹):"+file1.isDirectory()); System.out.println("此文件是否为可执行文件:"+file1.canExecute()); System.out.println("此文件是否为可读:"+file1.canRead()); System.out.println("此文件是否为可写:"+file1.canWrite()); System.out.println("文件的绝对路径:"+file1.getAbsolutePath()); System.out.println("文件名称:"+file1.getName()); System.out.println("文件的相对路径:"+file1.getPath()); System.out.println("文件的父目录:"+file1.getParent()); System.out.println("文件的最后一次修改时间:"+file1.lastModified()); System.out.println("文件的大小:"+file1.length()); } /** * 文件夹/目录分隔符: * * windows系统: \ * linux/unix系统: / * * * 路径与路径之间也有分隔符: * windows系统: 分号(;) * linux/unix系统: 冒号(:) * * 为了兼容各种文件系统的分隔符,File提供了分隔符常量来描述所在系统的分隔符 * * File.separator : 文件夹/目录分隔符 * File.pathSeparator : 路径与路径之间也有分隔符: * * * * 路径优缺点的总结: * * 绝对路径的优缺点: 写法简单, 只要不移动磁盘,就可以找到, 如果程序更换了的文件系统(磁盘),那么就找不到这个路径 * 相对路径的优缺点: 稍微复杂一点, 程序移动不会影响文件找不到(通常文件或者文件夹都是项目下的东西)。 * 如果项目下的某一个目录或者是文件移动了,那么就找不到了 * */ public static void separator(){ //写相对路径 File file1 = new File("."+File.separator+".."+File.separator+"d"+File.separator+"a.txt"); System.out.println(file1); } /** * 路径的分类: * 绝对路径:从文件系统目录结构的的最外层,也就是根开始写的一个路径(windows系统从盘符开始写,Linux/unix从根开始写) * * 相对路径:相对某一个路径(此路径会作为参照物)而写的路径 * . : 表示当前目录 * .. : 表示上一级目录 * * 练习: * 当前位置: D:\a\b\c\ * 使用绝对路径描述b里的d里的a.txt : D:\a\b\d\a.txt * 使用相对路径描述b里的d里的a.txt : ..\d\a.txt * */ public static void path(){ //使用绝对路径来描述一个File对象: 这个文件test6.txt在D盘下的io文件夹里 //所以:绝对路径的写法应该是:D:\io\test6.txt // 相对路径的写法,当前位置作为参照物(在源文件里写程序时, // 当前目录指的项目名那个目录D:\Users\Michael\Documents\IdeaProjects\hz2003-api) //因此写法如下:..\..\..\..\..\io\test6.txt //绝对路径: File file = new File("D:\\io\\test6.txt"); System.out.println(file); //相对路径: File file1 = new File("..\\..\\..\\..\\..\\io\\test6.txt"); System.out.println(file1); } /** * 构造器的使用 */ public static void constructor(){ /** * 第一个构造器:File(String name) * 解析:name 用于指定一个文件(文件夹)的路径 */ File file = new File("D:\\io\\test1.txt"); System.out.println(file); /** * 描述一个不存在的文件或文件夹 */ File file1 = new File("D:\\io\\test2.txt"); System.out.println(file1); /** * 第二个构造器:File(String parent,String child) * 解析:parent 用于指定一个父目录,是一个文件夹的路径 * child 用于指定parent下的一个子目录 */ File file2 = new File("D:\\io","test3.txt"); System.out.println(file2); File file3 = new File("D:\\io1","test4\\test5.txt"); System.out.println(file3); } }

    第二章 IO流

    IO流的用处

    IO流主要用来实现对文件的读写操作。

    IO流的分类

    按照数据流向分类: 输入流:数据从外部设备流向当前的程序(内存)中。输出流:从当前的程序(内存)中流向外部存储设备。 按照处理的数据分类: 字节流:数据是按照字节(byte)作为单位进行处理的,可以一次处理一个或多个字节。字符流:数据是按照字符(char)作为单位进行处理的,可以一次处理一个或多个字符,需要注意的是字符集。 按照流的功能分类 低级流(节点流):可以直接连接两个设备的流或者是直接连接一个设备和程序的流。高级流(过滤流):封装了低级流,可以更好的处理数据的流。

    流的继承关系

    继承关系图

    字节流

    字节流的的父类(抽象类)

    InputStream(字节输入流的父类)

    常用方法

    返回值方法介绍voidclose()关闭流intread()读取一个字节并转为int类型intread(byte[] bytes)()最多读取bytes.length个字节,返回值为读取的真实字节数intread(byte[] bytes, int off, int len)()从off处读取len个字节到bytes

    OutputStraem(字节输出流的父类)

    常用方法

    返回值方法介绍voidclose()关闭流voidflush()输出缓冲区中的数据voidwrite(int b)将int类型的b的低八位的字节写出去voidwrite(byte[] bytes)将bytes数组的所有字节写出voidwrite(byte[] bytes, int off, int len)将b中的字节从下标为off处开始写len个元素,写到输出流中

    常用字节流的应用

    FileInputStream

    构造方法

    参数介绍File file指定一个File对象创建一个文件输入流对象,File只能是文件,不能是目录String path指定一个字符串的路径来创建一个文件输入流对象

    FileOutputStream

    构造方法

    参数介绍File file指定一个File对象来获取一个文件输出流对象File file,boolean append指定一个File对象来获取一个文件输出流对象,可以指定是否对文件进行追加内容操作String path指定一个字符串对象来获取一个文件输出流对象String path, boolean append指定一个字符串对象来获取一个文件输出流对象,可以指定是否对文件进行追加内容操作

    代码实现

    package com.qf.io; import java.io.*; import java.util.Arrays; public class InputOutputStreamDemo { public static void main(String[] args) throws IOException { outStream2(); } /** * 两个参数的构造器 * 第二个参数:append 表示对要连接的文件,是否进行追加写。 * true: 表示追加写,不进行覆盖 * false: 表示覆盖,从头写。 * */ public static void outStream2(){ try(OutputStream os = new FileOutputStream("out.txt",true)){ byte[] bytes = "\n我带你爬山啊".getBytes(); os.write(bytes); }catch (IOException e){ e.printStackTrace(); } } /** * 一个参数的构造器 * @throws IOException */ public static void outStream1() throws IOException { //获取一个文件输出流对象 try(OutputStream os = new FileOutputStream(new File("out.txt"))){ //将数字97写入文件中 int num = 97; os.write(num); //此方法写入的是int类型的低八位。 byte[] bytes = "hello world".getBytes(); os.write(bytes); }catch (Exception e){ e.printStackTrace(); } /** * 输出流在关闭时,如果有缓冲区,会自动调用flush方法,将缓冲区的数据都写入到文件中 * 一个参数的构造器,在新建连接时,默认是覆盖操作,但是此次连接在终止前都是追加操作。 */ } /** * read方法的返回值如果是-1. 说明文件已经读完 * * 注意:读到文件的最后一次有数据的时候,还会再读取一次,返回-1,证明文件结束。 * */ public static void stream4(){ try(FileInputStream fis = new FileInputStream("D:\\academia\\aaa.txt")){ byte[] bytes = new byte[100]; int length = 0; int count = 0; while((length=fis.read(bytes))!=-1){ String str = new String(bytes,0,length); System.out.println(str); System.out.println("第"+(count++)+"次"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * io流关闭的特殊写法: */ public static void stream3(){ //实现了autoCloseable接口的流,如果写在try后的小括号里去声明和定义,当try{}模块的逻辑执行完,就会自动调用流的close方法进行关闭 // 无需大家写finally模块 try(InputStream is = new FileInputStream("a.txt")){ byte[] b = new byte[100]; int length = is.read(b); //将字节数组变成字符串 String str = new String(b,0,length); System.out.println(str); }catch (IOException e){ e.printStackTrace(); } } public static void stream2(){ /** * 使用流的正确方式: */ InputStream is = null; try { is = new FileInputStream("a.txt"); byte[] b = new byte[100]; int length = is.read(b); //将字节数组变成字符串 String str = new String(b,0,length); System.out.println(str); } catch (IOException e){ e.printStackTrace(); } finally { //finally模块一般用于释放资源,比如流关闭操作 try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } public static void stream1() throws IOException{ /** * 如果在使用输入流读取文件时,创建时指定的文件不存在,会报 * 文件找不到异常FileNotFoundException * * 创建一个输入流,程序与磁盘上的文件a.txt建立连接通道 */ InputStream is = new FileInputStream(new File("a.txt")); //调用read方法获取文件的第一个字节 int i = is.read(); System.out.println((char)i); i = is.read(); System.out.println((char)i); //调用read(byte[] b)方法 byte[] b = new byte[5]; int length = is.read(b); //将流中的数据读入到数组b中,返回的是真实读取的字节数量 System.out.println("length:"+length); System.out.println(Arrays.toString(b)); b = new byte[5]; length = is.read(b); //将流中的数据读入到数组b中,返回的是真实读取的字节数量 System.out.println("length:"+length); System.out.println(Arrays.toString(b)); // 最终,别忘记关闭流 is.close(); } }

    BufferedInputStream

    构造方法

    参数介绍InputStream in指定一个InputStraem对象获得一个字节缓冲输入流对象InputStream in, int size指定一个InputStraem对象和缓冲区大小获得一个字节缓冲输入流对象

    BufferedOutputStream

    构造方法

    参数介绍OutputStream in指定一个OutputStream对象获得一个字节缓冲输/出流对象OutputStream in, int size指定一个OutputStream对象和缓冲区大小获得一个字节缓冲输出流对象

    代码实现

    package com.qf.io; import java.io.*; public class BufferedInputOutputDemo { public static void main(String[] args) { bufferedOutput1(); } public static void bufferedOutput1(){ BufferedOutputStream bos = null; try{ bos = new BufferedOutputStream(new FileOutputStream("fileday02.txt")); //写数据 byte[] bytes = "hello world no zuo no die \n".getBytes(); /** * 写数据时,是将数据写入到内部维护的缓冲区里。 * 当缓冲区充满了数据,也会自动冲刷数据。 * 当一次性写的数据超过缓冲区,不会经过缓冲区。 */ bos.write(bytes); //手动调用一下flush方法 bos.flush(); bytes = "西方世界,非常好看".getBytes(); bos.write(bytes); bos.flush(); }catch (Exception e){ e.printStackTrace(); }finally { // 关闭流之前,会调用flush方法,将缓冲区的数据冲刷到文件中 try{ bos.close(); }catch (Exception e){ e.printStackTrace(); } } } /** * 测试一下字节缓冲输入流的构造器 * * 缓冲区: 实际上就是一个字节数组。 byte[] buf * * 原理:当使用字节缓冲输入流时,底层会先把文件中的数据读到缓冲区中,默认情况下,一次最多能读缓冲区的长度个。 * 然后在从缓冲区中将数据拷贝到我们自定义的数组中。 * * 特点:当我们自定义的数组的长度小于缓冲区的长度时,一定会使用缓冲区 * 如果大于缓冲区的长度,不会使用缓冲区,而是直接交互。 * * * 另一个构造器: BufferedInputStream(InputStream is,int size); * 此构造器可以决定内部缓冲区的大小。 */ public static void bufferedInput1(){ try(InputStream is = new BufferedInputStream(new FileInputStream("a.txt"))){ byte[] bytes = new byte[10240]; int length = 0; while((length = is.read(bytes))!=-1) { String str = new String(bytes, 0, length); System.out.println(str); } }catch (IOException e) { e.printStackTrace(); } } }

    DataInputStream

    构造方法

    参数介绍InputStream in指定一个InputStraem对象获得一个字节输入流对象

    DataOutputStram

    构造方法

    参数介绍OutputStream out指定一个OutputStream对象获得一个字节输出流对象

    代码实现

    package com.qf.io; import java.io.*; public class DataInputOutputDemo { public static void main(String[] args) { // dataOutput1(); dataInput1(); } /** * 读取时,一定要提前知道是什么类型的数据,然后调用相应的方法去读。 有一定的局限性。 */ public static void dataInput1(){ try(DataInputStream dis = new DataInputStream(new FileInputStream("filedata.txt"))){ byte b = dis.readByte(); System.out.println(b); short s = dis.readShort(); System.out.println(s); int num = dis.readInt(); System.out.println(num); long count = dis.readLong(); System.out.println(count); float f1 = dis.readFloat(); System.out.println(f1); double d1 = dis.readDouble(); System.out.println(d1); boolean flag = dis.readBoolean(); System.out.println(flag); char ch = dis.readChar(); System.out.println(ch); String str = dis.readUTF(); System.out.println(str); } catch (IOException e) { e.printStackTrace(); } } public static void dataOutput1(){ try(DataOutputStream dos = new DataOutputStream(new FileOutputStream("filedata.txt"))){ //写一个字节 dos.writeByte(10); //写一个short类型的数据 dos.writeShort(200); //写一个int类型的数据 dos.writeInt(32768); //写一个long类型的数据 dos.writeLong(1000); //写一个float类型的数据 dos.writeFloat(1.0f); //写一个double类型的数据 dos.writeDouble(2.3); //写一个boolean类型 dos.writeBoolean(true); //写一个char类型的数据 dos.writeChar('你'); //写一个字符串类型的数据 dos.writeUTF("我带你爬山"); } catch (IOException e) { e.printStackTrace(); } } }

    DataInputStream和DataOutputStream主要是新增了一些对基本数据类型进行操作的方法。

    DataInputStream和FileInputStream的区别

    字符流

    字符流的父类(抽象类)

    Reader(字符输入流父类)

    常用方法

    返回值方法介绍voidclose()关闭流intread()读取一个字符并转为int类型intread(char[] chs)最多读取chs.length()个字符到chs数组中,返回值为真实读取的个数intread(char[] chs, int off, int len)从off处读取len个字节到chs中

    Writer(字符输出流父类)

    常用方法

    返回值方法介绍voidclose()关闭流voidflush()输出缓冲区中的数据voidwrite(int c)写一个字符voidwrite(char[] chs)将chs数组的所有字节写出voidwrite(char[] chs, int off, int len)将b中的字节从下标为off处开始写len个元素,写到输出流中voidwrite(String str)将一个字符串写出voidwrite(String str, int off, int len)将一个字符串从off开始写len个字符

    常用字符流的应用

    FileReader

    构造方法

    参数介绍File file指定一个File对象获得一个字符输入流String path指定一个文件路径获得一个字符输入流

    FileWriter

    构造方法

    参数介绍File file指定一个File对象获得一个字符输出流File file, boolean append指定一个File对象获得一个字符输出流,并指定是否追加操作String path指定一个文件路径获得一个字符输出流String path, boolean append指定一个文件路径获得一个字符输出流,并指定是否追加操作

    代码实现

    package com.qf.io; import java.io.*; public class FileReaderWriterDemo { public static void main(String[] args) { // fileWriterDemo(); fileReaderDemo(); } public static void fileReaderDemo(){ /** * int read(): 读取一个字符,转成int类型 * read(char[] ch): 最多读取ch.length个字符存储到数组中 * read(char[] ch,int off,int length): 读取length个字符存储到数组中,从下标off开始 */ try(FileReader fr = new FileReader(new File("filewriter.txt"))){ char[] ch = new char[100]; int length = 0; while((length = fr.read(ch))!=-1){ String str = new String(ch,0,length); System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } } public static void fileWriterDemo(){ /** * 重载的写出方法 * * void write(int num):写一个字符 * void write(char[] ch) * void write(char[] ch,int off,int len) * void write(String str) * void write(String str,int off,int len) */ try(FileWriter writer = new FileWriter("filewriter.txt",true)){ writer.write('你'); writer.write(new char[]{'好','世','界'}); writer.write(new char[]{'h','e','l','l','o'},1,3); writer.write("welcome to 中国"); writer.write("hellokitty",5,5); } catch (IOException e) { e.printStackTrace(); } } }

    BufferedReader

    构造方法

    参数介绍Reader read指定一个Reader对象获得一个字符缓冲输入流Reader read, int size指定一个Reader对象获得一个字符缓冲输出流,并指定缓冲区大小
    特有方法
    返回值方法介绍StringreadLine()读取缓冲流中的一行数据, 可以逐行读取。 一直到读取到的数据是null, 表示数据读取完,readLine() 是逐行读取, 但是, 只能读取到一行中的内容, 并不能读取走换行符

    BufferedWriter

    构造方法

    参数介绍Writer write指定一个Writer对象获得一个字符缓冲输出流Writer write, int size指定一个Writer对象获得一个字符缓冲输出流,并指定缓冲区大小

    代码实现

    package com.qf.io; import java.io.*; /** * BufferedReader/BufferedWriter内部都维护者一个字符缓冲区。 * * 读取时,会先读取到缓冲区中,然后从缓冲区拿到我们想要的字符。 * 写数据时,会先写入缓冲区中,然后会调用flush方法冲刷缓冲区的数据到文件中。 */ public class BufferedReaderWriterDemo { public static void main(String[] args) { // bufferedWriterDemo(); bufferedReaderDemo(); } public static void bufferedReaderDemo(){ BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader( new FileInputStream("bufferwriter.txt"),"utf-8")); String str = ""; /** * String readLine() * 解析:用于读取文件的一行内容,返回的是这一行内容,但是不包含换行符。 * 如果读到文件末尾,返回null. 而不是-1。 */ while((str=br.readLine())!=null){ System.out.print(str); } } catch (Exception e) { e.printStackTrace(); } finally { if(br!=null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void bufferedWriterDemo(){ BufferedWriter bw = null; try{ bw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream("bufferwriter.txt"),"UTF-8")); bw.write("你喜欢我吗?\n"); bw.newLine(); bw.write(" i hate you"); }catch (Exception e){ e.printStackTrace(); }finally { try { bw.close(); } catch (Exception e) { e.printStackTrace(); } } } }

    InputStreamReader

    构造方法

    参数介绍InputStream in指定一个字节流,使用默认字符集来获取一个转换输入流对象InputStream in, String charsetName指定一个字节流和字符集来获取一个转换输入流对象

    OutputStreamWriter

    构造方法

    参数介绍OutputStream out指定一个字节输出流,使用默认字符集,获取一个转换输出流对象OutputStream out, String charsetName指定一个字节输出流,同时指定一个字符集,获取一个转换输出流对象

    代码实现

    package com.qf.io; import java.io.*; /** * */ public class StreamReaderWriterDemo { public static void main(String[] args) { // inputStreamReader(); outputStreamWriter(); } public static void outputStreamWriter(){ OutputStreamWriter osw = null; try{ osw = new OutputStreamWriter( new BufferedOutputStream( new FileOutputStream("peotry1.txt")),"GBK"); osw.write("\n你好"); osw.write("你好"); }catch (Exception e){ e.printStackTrace(); }finally { try { osw.close(); } catch (Exception e) { e.printStackTrace(); } } } public static void inputStreamReader(){ try(InputStreamReader isr = new InputStreamReader( new BufferedInputStream(new FileInputStream("peotry.txt")) ,"UTF-8")){ char[] ch = new char[50]; int length = 0; while((length = isr.read(ch))!=-1){ String string = new String(ch,0,length); System.out.println(string); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }

    PrintWriter

    构造方法

    参数介绍File file指定一个File对象得到一个PrintWriter对象File file, String csn指定一个File对象和字符集,得到一个PrintWriter对象OutputStream out指定一个OutputStream对象得到一个PrintWriter对象OutputStream out, boolean autoFlush指定一个OutputStream对象得到一个PrintWriter对象,设置是否自动冲刷String fileName指定一个文件路径获得一个PrintWriter对象String fileName, String csn指定一个文件路径和字符集获得一个PrintWriter对象Writer out指定一个Writer对象获得一个PrintWriter对象Writer out, boolean autoFlush指定一个Writer对象获得一个PrintWriter对象,设置是否自动冲刷

    代码实现

    package com.qf.io; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; /** * PrintWriter类型 * 1. 提供了多个构造器, * 2. 提供了可以写各种类型的方法 * 3. 可以用来指定是否自动冲刷缓冲区。 */ public class PrintWriterDemo { public static void main(String[] args) { PrintWriter pw = null; try { pw = new PrintWriter(new FileOutputStream("printwriter.txt"),true); // // pw.print(15); // pw.print("你好世界\n"); /** * 如果想要达到自动冲刷的效果,除了调用相关构造器,传入true之后, * 还应该调用println(X x). */ pw.println("hello world"); pw.println("hello kitty"); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if(pw!=null){ pw.close(); } } } }

    序列化

    什么是序列化

    将内存中的对象 转成二进制字节序列 ,这个过程就是序列化(new Student(“张三”,23,‘男’)-------------------->00100101010101010111110101010110…)

    什么是反序列化

    将二进制字节序列转成内存中的对象,这个过程就是反序列化(00100101010101010111110101010110…-------------------->new Student(“张三”,23,‘男’))

    代码实现

    public static void serialize(List<Person> list) throws IOException { ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("xxdd.txt")); os.writeObject(list); os.close(); } public static void deserialize() throws Exception { ObjectInputStream os = new ObjectInputStream(new FileInputStream("xxdd.txt")); List<Person> list; list = (List<Person>) os.readObject(); list.forEach(System.out::println); }

    需要序列化的类必须实现Serializable接口,并设置serialVersionUID属性,如果不设置serialVersionUID,当类的属性发生改变时反序列化会失败

    第三章 NIO

    和传统IO流区别

    IO是面向流的,NIO是面向缓冲区的IO是阻塞的,NIO是非阻塞的

    Buffer缓冲区

    Buffer缓冲区概念

    缓冲区是一个用来存储基本数据类型的一个容器, 类似于一个数组。缓冲区, 可以按照存储的数据类型不同, 将缓冲区分为:ByteBuffffer、 ShortBuffffer、IntBuffffer、LongBuffffer、FloatBuffffer、DoubleBuffffer、CharBuffffer但是, 要注意, 并没有BooleanBuffffer!这些缓冲区, 虽然是不同的类, 但是他们拥有的相同的属性和方法。 因为他们都继承自相同的父类Buffffer。

    Buffer缓冲区的属性

    capacity:缓冲区的容量,缓冲区一旦开辟,无法修改limit:缓冲区可操作数的个数position:位置,表示当前要操作缓冲区数据的下标mark:打标机

    Buffer缓冲区的方法

    常用方法(以byteBuffer为例)

    返回值方法介绍byteBufferallocate(int capacity)获取一个byteBuffer的对象intcapacity()获取缓冲区的容量intlimit()获取缓冲区当前可操作数的个数intposition()获取位置,表示当前要操作缓冲区数据的下标ByteBufferput(byte b)写入一个字节,position向后移动一位ByteBufferput(byte[] bs)将字节数组写入缓冲区中,position向后移动bs.length位Bufferfiip()转为读模式,将positon设置为0,limit设置为之前position值ByteBufferget()读取一个字节的数据ByteBufferget(byte[] bs)读取bs.length个元素进bs数组中Buffermark()在缓冲区中添加一个标记, 将mark属性的值设置为当前的position的值,一般配合reset使用Bufferreset()将属性position的值, 修改为mark记录的值Bufferrewind()倒回, 将position的值重置为0, 同时清空mark的标记的值Bufferclear()重置所有的属性为缓冲区刚刚被开辟时的状态,position = 0,limit = postion

    allocate,get,put属于子类的方法

    capacity >= limit >= position >= mark

    写模式就是将数据写入缓冲区,读模式就是从缓冲区读取数据,刚开辟时默认是写模式

    其实, 缓冲区中, 并没有所谓的真正意义上的读模式和写模式。 其实所谓“读模式”和“写模式”, 只是逻辑上的区分。一个处于“读模式”下的缓冲区, 依然可以写数据。 一个处理“写模式”下的缓冲区, 依然可以读取数据。上述方法中, 基本所有的方法, 都是围绕着缓冲区中的几个属性进行的。

    直接缓冲区

    非直接缓冲区, 是在JVM中开辟的空间。 allocate(int capacity)直接缓冲区, 是直接在物理内存上开辟的空间。 allocateDirect(int capacity)isDirect() 方法判断是否是直接缓冲区

    Channel通道

    简介:通道Channel, 就是文件和程序之间的连接。 在NIO中, 数据的传递, 是由缓冲区实现的, 通道本身

    并不负责数据的传递。

    获取通道的三种方式

    使用IO流中的FileInputStream 和FileOutputStream来获取

    public class ChannelDemo01 { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; try{ fis = new FileInputStream("peotry.txt"); fos = new FileOutputStream("peotry1.txt"); FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); //调用通道的read方法,传入一个缓冲区对象,用于读取数据,存储到缓冲区,如果返回-1.说明没有数据了 while((inChannel.read(buffer))!=-1){ buffer.flip(); // 切换读模式,position变为0,limit变为存储的元素的个数 outChannel.write(buffer); //为下一次继续读数据到buffer里做准备 buffer.clear(); } }catch (Exception e){ e.printStackTrace(); }finally { try{ if(fis!=null){ fis.close(); } if(fos!=null){ fos.close(); } }catch (Exception e){ e.printStackTrace(); } } } }

    使用FileChannel.open()

    public class ChannelDemo02 { public static void main(String[] args) { try(FileChannel inChannel = FileChannel.open(Paths.get("peotry.txt"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("peotry2.txt"),StandardOpenOption.WRITE,StandardOpenOption.CREATE,StandardOpenOption.APPEND)){ ByteBuffer buffer = ByteBuffer.allocate(1024); //调用通道的read方法,传入一个缓冲区对象,用于读取数据,存储到缓冲区,如果返回-1.说明没有数据了 while((inChannel.read(buffer))!=-1){ buffer.flip(); // 切换读模式,position变为0, limit变为存储的元素的个数 outChannel.write(buffer); //为下一次继续读数据到buffer里做准备 buffer.clear(); } } catch (IOException e) { e.printStackTrace(); } } }

    使用Files工具类里的newXXXXX方法

    public class ChannelDemo03 { public static void main(String[] args) throws IOException { FileChannel inChannel = (FileChannel) Files.newByteChannel(Paths.get("peotry.txt"), StandardOpenOption.READ); FileChannel outChannel = (FileChannel) Files.newByteChannel(Paths.get("peotry3.txt"),StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW); ByteBuffer buffer = ByteBuffer.allocate(1024); //调用通道的read方法,传入一个缓冲区对象,用于读取数据,存储到缓冲区,如果返回-1.说明没有数据了 while((inChannel.read(buffer))!=-1){ buffer.flip(); // 切换读模式,position变为0, limit变为存储的元素的个数 outChannel.write(buffer); //为下一次继续读数据到buffer里做准备 buffer.clear(); } } }

    NIO实现文件的复制

    public static void copy() throws IOException { FileChannel inChannel = null; FileChannel outChannel = null; try { inChannel = FileChannel.open(Paths.get("source.txt"), StandardOpenOption.READ); outChannel = FileChannel.open(Paths.get("file/data.txt"),StandardOpenOption.WRITE,StandardOpenOption.CREATE,StandardOpenOption.APPEND); ByteBuffer buffer = ByteBuffer.allocate(1024); while((inChannel.read(buffer))!=-1){ buffer.flip(); outChannel.write(buffer); buffer.clear(); } } catch (Exception e) { e.printStackTrace(); } finally { if (inChannel != null) inChannel.close(); if (outChannel != null) outChannel.close(); } }

    Files工具类

    public class FilesDemo { public static void main(String[] args) throws IOException { //创建一级文件夹(如果这个文件夹存在,会抛异常) // Files.createDirectory(Paths.get("dir1")); //创建多级文件夹(如果需要创建的文件夹存在,不会抛出异常) // Files.createDirectories(Paths.get("dir2/dir3/dir4")); // 3. 创建一个文件(如果这个文件已存在,重复创建会异常) // Files.createFile(Paths.get("dir1\\file")); // 4. 删除一个文件或者空文件夹(如果要删除的文件或空文件夹不存在,会抛异常;如果删除的 不是一个空文件夹也会抛异常) // Files.delete(Paths.get("dir1\\file")); // // 5. 删除一个文件或者空文件夹(如果删除失败,不会抛异常,返回false) // Files.deleteIfExists(Paths.get("dir1\\file")); // 6. 移动文件(重命名) // Files.move(Paths.get("dir1"), Paths.get("dir3")); // 7. 拷贝文件 // Files.copy(Paths.get("peotry.txt"), Paths.get("peotry4.txt")); // } }
    Processed: 0.011, SQL: 9