Juan基础28(文件操作和IO流)
编程的本质是用于处理数据——
将数据保留在文件等其他物理设备上,保证数据可以永久保存
File
类
既可以代表文件,也可以代表目录
可以创建、删除、重命名,但不能读取文件的内容
绝对路径:以根路径(盘符)开头的路径叫绝对路径
相对路径:不是绝对路径的路径(
基本用法
- 创建对象
- 调用方法(自己查文档(
举个栗子
import java.io.File;
public class Demo1 {
public static void main(String[] args) throws Exception {
File f=new File(".");//将目录包装File
File f1=new File("src");//将文件包装File
File 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);
}
}
}
/*
true
true
true
E:\Java\UsingFilesAndIO\.
E:\Java\UsingFilesAndIO
C:\
D:\
E:\
F:\
.idea
out
src
UsingFilesAndIO.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();
}
}
/*
13
10
105
109
112
111
114
116
*/
此处在第一行故意加了一个空行,目的是输出显示回车和换行\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")));
//此时输出对象从屏幕改成了文件wyd
System.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();
//创建并添加JPanel
JPanel 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);
}
}