I/O输入输出流
File类
构造方法
指定文件路径指定父目录路径和文件名指定父目录的对象和文件名指定URI统一资源标识符 常用方法
访问文件属性方法 *** 作方法 文件过滤器递归读取文件清理空文件夹 IO流
文件分类流的分类字节流
InputStream
FileInputStreamByteArrayInputStream OutputStream
FileOutputStreamByteArrayOutputStream 文件复制序列化和反序列化
ObjectOutputStream 序列化 *** 作ObjectInputStream 反序列化 *** 作 缓冲字节流 字符流
文件输入输出流缓冲输入输出流
BufferedReader&BufferedWriter out&in 转换流
PrintWriter 随机读写流文件加密
I/O输入输出流 File类java.io.file
表示电脑上的文件或者目录
无论是文件还是目录都通过File类表示提供了对文件和目录的基本 *** 作,如查看文件名,文件大小,新建或删除文件File不能访问文件的内容,需要I/O输入输出流访问文件的内容 构造方法 指定文件路径
File file = new File(path);
创建File文件时只是创建一个指向某个路径的对象,并不表示在硬盘中创建文件,这个路径指向的文件可以存在,也可以不存在。
绝对路径
以根路径开始的路径
关于路径分隔符(由于我的系统是Linux系统,故只说明Linux系统下的情况)
例:/home/Desktop/a.txt相对路径
不是以根开始的路径,相对于某个路径的路径,.表示当前目录,…表示上一级目录。相对路径的父目录默认的是项目根目录
指定父目录路径和文件名
File file = new File(father path, filepath);指定父目录的对象和文件名
File file = new File(File fatherfile, filepath);指定URI统一资源标识符
URL需要装换成URI使用
常用方法 访问文件属性方法需要用到文件过滤的过滤器接口,重写过滤方法。例程如下:
public static void main(String[] args) { File file1 = new File("/data/JAVAProjects/Wangdao2022LF/File/src/com/file/test"); //String[] list = file1.list(); String[] list = file1.list(new FilenameFilter() { @Override public boolean accept(File file, String name) { return name.endsWith("png") || name.endsWith("gif") || name.endsWith("jpg"); } }); System.out.println(Arrays.toString(list)); }递归读取文件
在一般情况下,文件的路径有可能是一般文件,也有可能是文件目录,这时可以使用递归的思想,获取文件目录及其子目录下的所有文件。
代码实现如下:
public static void getFiles(File filePath){ if(filePath.exists()){ if(filePath.isFile()){ System.out.println(filePath.getAbsolutePath());//如果目标文件是一 //般文件,直接输出文件绝对路径 } else{ System.out.println(filePath.getAbsolutePath());//目标文件是目录 //文件,直接输出目录绝对路径 File[] files = filePath.listFiles(); for(File f : files){ if(f.isFile()) System.out.println(f.getAbsolutePath()); else getFiles(f);//此处使用递归,当子文件中含有目录的时候再次调 //用该函数,将子目录当成新的filePath参数,实现递归 } } } }清理空文件夹
public static void removeEmptyDirectory(File file){ if(file.isDirectory()&& Objects.requireNonNull(file.listFiles()).length==0){ file.delete(); System.out.println("删除空目录" + file.getAbsolutePath()); removeEmptyDirectory(file.getParentFile()); } else if (file.isDirectory()){ File[] files = file.listFiles(); for(File f : files != null ? files : new File[0]){ removeEmptyDirectory(f); } } }IO流
可以理解成一组有顺序的、有起点有中点的动态数据集合
文件是数据在硬盘上的静态存储
流是传输时的动态形态
文本文件
可以用记事本打开的文件,由字符组成二进制文件
除文本以外的文件都是二进制文件
流的分类
流的方向:
输入流:由InputStream,Reader作为父类
输出流:由OutputStream,Writer作为父类按流中数据的单位
字节流byte:由InputStream,OutputStream作为父类
字符流char:由Reader,Writer作为父类按数据的来源
节点流:直接对数据进行 *** 作
包装流:对一个节点流进行 *** 作
字节流
InputStream
方法 作用
//JDK7中提供了一种新语法,叫try-with-source,能够自动关闭外部资源,无需手动关闭 //此处只能创建对象,而且只能创建那些有实现了AutoClosable接口的对象 try(FileInputStream fis = new FileInputStream("test.txt")){ byte[] buffer = new byte[3];//buffer数组储存在文件缓冲区,而且不是实际内存而是JVM int num = fis.read(buffer);//减少对硬盘的读取次数,返回值是实际读取的字节数,如果读取到末尾返回的是-1 } catch (IOException e){ e.printStackTrace(); }ByteArrayInputStream
字节数组输入输出流 *** 作的是内存,不是外部设备因此无需关闭流
public static void byteArrayInputStream(){ byte[] bytes = "hello world".getBytes(); try{ InputStream is = new ByteArrayInputStream(bytes); int i = -1; while((i = is.read())!= -1){ System.out.println((char)i); } } catch (IOException e) { e.printStackTrace(); } }OutputStream
public static void main(String[] args) { FileOutputStream fos = null; try{ //如果文件不存在,会自动创建文件;如果文件存在,则会覆盖重写,但是在构造时,能够使用重载的构造方法追加写入数据 //fos = new FileOutputStream("test.txt"); fos = new FileOutputStream("test.txt", true); byte[] data = "hello world".getBytes(); fos.write(data);//只是把数据写入到缓冲区中 fos.flush();//将缓冲区的数据刷新,写入到文件中,但是当关闭输出流时,会自动调用该方法 }catch (IOException e){ e.printStackTrace(); } }ByteArrayOutputStream
public static void byteArrayOutputStream(){ OutputStream os = new ByteArrayOutputStream(); try { os.write("hello,world".getBytes()); os.flush(); } catch (IOException e) { e.printStackTrace(); } System.out.println(os); }文件复制
每次复制一个字节,因为涉及到多次IO *** 作,传输时间更长
int data = -1; while((data = is.read()) != -1){ os.write(data); } //488ms //文件复制成功!
再看看多字节,我们一次复制1MB大小的字节数组
byte[] buffer = new byte[1024 * 1024]; int num = -1; while((num = is.read(buffer))!=-1){ os.write(buffer, 0, num); } //1ms //文件复制成功!
时间就相差很大了。
序列化和反序列化序列化:将Java对象写入到IO流中,实现将对象保存在磁盘上或者在网络中传递对象
反序列化:从IO流中读取Java对象,实现从磁盘和网络上恢复对象
要求:
对象必须实现Serializable接口才能序列化,转换成二进制流,通过网络进行传输
ObjectOutputStream和ObjectInputStream都属于包装流
用于对节点流功能进行扩展创建包装流时,需要传入 *** 作的节点流对象关闭流时,只需要关闭包装流,节点流也会被关闭
ObjectOutputStream用于序列化,将对象写入二进制文件:
User user = new User(1001, "tom", 18); try { FileOutputStream fos = new FileOutputStream("user.data");//用来包装的流 ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(user); oos.flush(); } catch (IOException e) { e.printStackTrace(); }ObjectInputStream 反序列化 *** 作
注意事项:
对象必须实现Serializable接口,才能被序列化转换成二进制流通过网络传输;如果成员变量有对象属性,则对象属性也要序列化通过serialVersionUID用来判断序列化版本的一致性(反序列化时将流中携带的UID和本地相应实体的UID是否一致,才能进行反序列化)transient和static修饰的成员不会被序列化 缓冲字节流 字符流
Reader和Writer
文件输入输出流/字符流不能 *** 作二进制文件,只能 *** 作文本文件
try (FileWriter writer = new FileWriter("noun.txt"); FileReader reader = new FileReader("verb.txt")) { char[] buffer = new char[5]; int num = -1;//每次读取一个字符,返回int类型的值,可以读汉字,不会出现乱码 while ((num = reader.read(buffer)) != -1) writer.write(buffer, 0, num); System.out.println("文件复制成功"); } catch (IOException e) { e.printStackTrace(); }缓冲输入输出流
缓冲输入输出流属于包装流,为字符添加缓冲的功能,当读取或者写出数据时,先放到缓冲区,再到缓冲区读取。
BufferedReader&BufferedWritertry( BufferedReader reader = new BufferedReader(new FileReader("test.txt")); BufferedWriter writer = new BufferedWriter(new FileWriter("verb.txt")) ) { String data;//每次读一行,读不到数据返回null while((data = reader.readLine()) != null) writer.write(data); System.out.println("复制成功"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }out&in
System.out :标准输入输出流,默认为显示器
System.in :标准输入流,默认为键盘
只能由字节流转换成字符流,同时可以实现编码的转换
PrintWriter打印流,可以直接打印输出;’可以只以文件名作为参数
随机读写流随机读写流是一个字节流,可以定义到任意的文件位置进行读写 *** 作,使用该流既能读取文件又能写入文件。
System.out.println(raf.getFilePointer()); raf.seek(3);//使指针移动到指定位置 raf.skipBytes(2);//指针往后跳过多少个字节,不能反着走 System.out.println((char)raf.read());文件加密
思想:将文件里的字节与int类型密码异或得到加密后的字符存到密码,然后对密码文件的每个字节和密码进行异或即可还原原来数据。
public static void secret(String filePath, int password) { String newFilePath, notice; if(filePath.endsWith(".sec")) { newFilePath = filePath.substring(0, filePath.length() - 4); notice = "解密完成!"; } else { newFilePath = filePath + ".sec"; notice = "加密完成!"; } try( FileInputStream fis = new FileInputStream(filePath); FileOutputStream fos = new FileOutputStream(newFilePath); ) { int data = -1; while((data = fis.read()) != -1){ fos.write(data ^ password); } System.out.println(notice); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { Scanner sc = new Scanner(System.in); secret("test.txt.sec", 9527); }
加密后,由于生成的是二进制文件,显示出来是乱码:
߈�ф�ѯ�ߵ�߬�ߦ�ޏ�
解密后显示正常:
这波是肉蛋葱鸡
I/O部分到这里就结束了~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)