Juan基础28(文件操作和IO流)
编程的本质是用于处理数据——
将数据保留在文件等其他物理设备上,保证数据可以永久保存
File类
既可以代表文件,也可以代表目录
可以创建、删除、重命名,但不能读取文件的内容
绝对路径:以根路径(盘符)开头的路径叫绝对路径
相对路径:不是绝对路径的路径(
基本用法
- 创建对象
- 调用方法(自己查文档(
举个栗子
import java.io.File;public class Demo1 {public static void main(String[] args) throws Exception {File f=new File(".");//将目录包装FileFile f1=new File("src");//将文件包装FileFile f2=new File("E:/","Java");System.out.println(f.exists());System.out.println(f1.exists());System.out.println(f2.exists());System.out.println(f.getAbsolutePath());System.out.println(f.getCanonicalPath());File[] files=File.listRoots();for(File ff:files){System.out.println(ff);}String[] flist=f.list();for(String flist1:flist){System.out.println(flist1);}}}/*truetruetrueE:\Java\UsingFilesAndIO\.E:\Java\UsingFilesAndIOC:\D:\E:\F:\.ideaoutsrcUsingFilesAndIO.iml*/
递归方法遍历文件
import java.io.File;import java.nio.file.Files;public class See {public static void main(String[] args) {File start=new File("E:/C# C++");access(start);}public static void access(File start) {File[] subfiles=start.listFiles();for(File sub:subfiles){if (sub.isFile()){System.out.println("正在进入"+sub);}else if(sub.isDirectory()){System.out.println("进入"+sub+"目录");access(sub);}}}}
IO流
可以读取文件的内容
可以input、output各种物理结点的数据
流的分类
- 按方向
- 输入流——读取数据
- 输出流——写出数据
分辨二者,要从运行程序所在的内存来看:
- 如果数据是从程序自身流出,用输出流
- 如果我们的数据是流入程序自身,用输入流
- 按数据单元
- 字节流——每个水滴就是一个字节,每次读或者写一个字节,每个
Byte是计算机管理数据的最小单元
因此字节流可以读写任意文件 - 字符流——每个水滴就是一个字符,每次读或者写一个字符
可以非常方便的读写文本文件
分辨方式:
- 字节流以
Stream结尾 - 字符流以
Read和Write结尾
我们可以把输入和输出流比作一个水管,每一个单位看做水管里的一滴水fromat
- 按照角色来分类
- 节点流:代表数据源的IO结点
- 处理流(过滤流、包装流):建立在其他流的基础之上,用于对其他的流进行包装
IO流的基本方法
- 输入流的基本方法:
read():每次读取一滴水int read(xxx[] buff):读取N滴水到数组中,返回实际读取的水滴数int read(xxx[] cbuf,int off,int len)读取数组中间的一段
- 输出流的基本方法
write(int)输出一滴水void write(xxx[] buff)读取N滴水到数组中,返回实际的水滴数void write(xxx[] cbuf,int off,int len)读取数组中间的一段
节点流
| 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 | |
|---|---|---|---|---|
| 抽象基类 | InputStream |
OutputStream |
Reader |
Writer |
| 文件 | **FileInputStream** |
**FileOutputStream** |
**FileReader** |
**FileWriter** |
| 数组 | ByteArrayInputStream |
ByteArrayOutputStream |
CharArrayReader |
CharArrayWriter |
| 字符串 | StringInputStream |
StringOutputStream |
StringReader |
StringWriter |
输入流举例
import javax.imageio.IIOException;import java.io.FileInputStream;import java.io.FileNotFoundException;public class FileInputStreamTest {public static void main(String[] args) throws Exception {FileInputStream fis=new FileInputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\FileInputStreamTest.java");System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());fis.close();}}/*1310105109112111114116*/
此处在第一行故意加了一个空行,目的是输出显示回车和换行\n\r对应的数值就是13和10
打印程序本身的案例
import javax.imageio.IIOException;import java.io.FileInputStream;import java.io.FileNotFoundException;public class FileInputStreamTest {public static void main(String[] args) throws Exception {FileInputStream fis=new FileInputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\FileInputStreamTest.java");byte[] buff=new byte[512];//创建变量及时记录已被读取的字节数量int hasRead =0;//只要读取的量仍然大于0(仍然在读取非空字节),就继续循环while ((hasRead= fis.read(buff))>0) {//将读取的字节转化为字符串String a = new String(buff, 0, hasRead);System.out.println(a);//读取几个字节,就恢复几个字节}//记得关掉文件fis.close();}}
字节流换汤不换药
import javax.imageio.IIOException;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileReader;public class FileReaderTest {public static void main(String[] args) throws Exception {FileReader fis=new FileReader("E:\\Study\\Java\\UsingFilesAndIO\\src\\FileInputStreamTest.java");System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());System.out.println(fis.read());int hr=0;char[] a=new char[512];while ((hr=fis.read(a))>0){String ss=new String(a,0,hr);System.out.println(ss);}fis.close();}}
输出流
只要创建了输出流,就相当于得到了一个空的水管。
同样,字节流接收字节byte,字符流接收字符char
import java.io.FileOutputStream;import java.nio.charset.StandardCharsets;public class FileOutputTest {public static void main(String[] args) {FileOutputStream fos=null;try{//创建输出流fos=new FileOutputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\a.txt");//每次输出一个字符fos.write(13);fos.write(10);fos.write('f');//输出流读取字符集,用UTF-8将字符串转化成字节数组fos.write("可还行".getBytes(StandardCharsets.UTF_8));}catch (Exception ex){//处理异常System.out.println("出现异常");ex.printStackTrace();}finally {try {assert fos != null;fos.close();}catch (Exception ex){//处理异常ex.printStackTrace();}}}
文件复制
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class Copy {//文件拷贝的本质就是对需要拷贝的文件进行及时的读写操作public static void main(String[] args) {try(FileInputStream fos=new FileInputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\a.txt");FileOutputStream fis=new FileOutputStream("E:\\Study\\Java\\UsingFilesAndIO\\src\\copy.txt");){byte[] buff=new byte[512];int hasRead=0;while ((hasRead=fos.read(buff))>0){//保证读了多少内容就写内容fis.write(buff,0,hasRead);}}catch (IOException ex){System.out.println("确定文件是否存在");ex.printStackTrace();}}}
IO流读取写字符串的数据
import java.io.ByteArrayInputStream;import java.io.IOException;import java.nio.charset.StandardCharsets;public class ArrayUsingTest {public static void main(String[] args) throws IOException {//将字符串转换为字符数组byte[] bytes="wy212".getBytes(StandardCharsets.UTF_8);ByteArrayInputStream bis=new ByteArrayInputStream(bytes);byte[] buff=new byte[512];int hasRead=0;while ((hasRead=bis.read(buff))>0){String str=new String(buff,0,hasRead);System.out.println(str);}}}
import java.io.ByteArrayOutputStream;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Arrays;public class ArrayUsingTest2 {public static void main(String[] args) {try (//基于一个长度为32的数组创造了IO数组流,相当于得到了一个空的水管ByteArrayOutputStream bos=new ByteArrayOutputStream();){//对于字节数组输出流而言,所有数据都被输出到底层的数组中byte[] a1="fucking".getBytes(StandardCharsets.UTF_8);bos.write(a1);System.out.println(Arrays.toString(a1));}catch (IOException ex){ex.printStackTrace();}}}
过滤流与缓冲流(要建立在已有的节点流的基础之上)
| 抽象基类 | FilterInputStream |
FilterOutputStream |
FilterReader |
FilterWriter |
|---|---|---|---|---|
| 缓冲流 | BufferedInputStream |
BufferedOutputStream |
BufferedReader |
BufferedWriter |
| 打印流 | PrintStream |
PrintWriter |
||
| 转换流 | InputStreamReader |
OutputStreamWriter |
||
| 特殊流 | DataInputStream |
DataOutputStream |
||
| 对象流 | ObjectInputStream |
ObjectOutputStream |
内存速度远大于外设(磁盘,网络)速度
如果内存输出一个数据单元,然后外设就处理一个单元,必须等外设处理好数据单元之后,内存才会再输出下一个单元,必然会造成一个程序的性能浪费——此时就需要添加一个缓冲流
内存先把所有的数据输出到缓冲——缓冲中的数据留给外设慢慢处理
当你使用缓冲流的时候,必须使用flush()方法将数据”冲“到底层的物理设备中(想象一下奥利给在马桶里堆积)
当然,close()命令中也自带flash()命令
BufferedReader可以每次读取一行
包装流存在的意义
Java创造包装流来消除底层节点流的差异
输入流常用BufferedReader
import java.io.BufferedReader;import java.io.FileReader;public class BufferTest {public static void main(String[] args) throws Exception{try (//作为过滤流,因此需要建立在其他流的基础之上BufferedReader bf=new BufferedReader(new FileReader("src/FileOutputTest.java"));) {String line = null;while ((line = bf.readLine()) != null) {System.out.println(line);}}}}
输出流常用PrintStream
import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintStream;public class PrintStreamTest {public static void main(String[] args) throws IOException {PrintStream ps =new PrintStream(new FileOutputStream("src/copy.txt"));//输出到文件ps.println("离离原上谱");ps.println("葛涛宁YYDS");ps.close();//此时文本copy就会被输入上面的两行文字}}
转换流
负责将字节流转换为字符流
- 理论上字节流比字符流功能更加强大
- 但是有时,当文件中只需要使用字符时,需要该种转换
功能——传入一个字节流,就会传出字符流
特殊流
DateInputStream 提供了系列ReadXxx()专门用于读取不同类型的数据
DataOutputStream 提供了系列WriteXxx()专门用于写入不同类型的数据
(Xxx代表数据类型)
二者都是通过Java的内部格式来记录数据的
因此DataOutputStream输出的数据应该使用DateInputStream来读取
重定向标准输入输出
标准输出就是电脑屏幕
System.setOut()可以换掉标准输出的对象
举例:
import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintStream;public class Printout {public static void main(String[] args) throws IOException {System.setOut(new PrintStream(new FileOutputStream("src/wyd.txt")));//此时输出对象从屏幕改成了文件wydSystem.out.println("f**k");System.out.println("wtf");System.out.println("language");}}
标准输入就是电脑键盘
System.setIn()可以换掉标准输入的对象
读取进程的数据
Ruhntime类有一个exec()方法可以用于运行平台上的程序,程序运行之后就变成了进程,因此该方法就返回运行的进程
Process就是进程,该对象提供了一些方法
InputStream getErrorStream()返回错误的流InputStream getInputStream()返回普通的输入流OutputStream getOutputStream()返回普通的输出流
(从Zeal粘的)
实例——简易的编译工具
import javax.swing.*;import java.awt.*;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.nio.charset.StandardCharsets;import java.util.Arrays;public class Compare {public static void main(String[] args) {//创建窗口JFrame JF=new JFrame("编译工具");//单例模式设计,只会产生一个实例Runtime rt=Runtime.getRuntime();//创建并添加JPanelJPanel JP=new JPanel();JF.add(JP,BorderLayout.NORTH);//创建多行文本域JTextArea jta=new JTextArea(10,80);jta.setEditable(false);jta.setBackground(Color.lightGray);//创建并添加单行的文本框JTextField jtf=new JTextField(80);JP.add(jtf);JButton jb=new JButton("编译");JP.add(jb);jb.addActionListener(e ->{String cmd = "javac -d . " + jtf.getText().trim();Process p;try {p = rt.exec(cmd);} catch (IOException ex) {throw new RuntimeException(ex);}StringBuilder sb = new StringBuilder();try(BufferedReader br=new BufferedReader(new InputStreamReader(p.getErrorStream()))){String line;while ((line=br.readLine())!=null){sb.append(Arrays.toString(line.getBytes(StandardCharsets.UTF_8))).append("\n");}//没有读到错误信息if(sb.toString().length()==0){jta.setText("编译完成");}else {jta.setText(sb.toString());}}catch (IOException ex) {throw new RuntimeException(ex);}});JF.add(new JScrollPane(jta));JF.pack();JF.setVisible(true);JP.setVisible(true);}}
