文件操作和IO

认识文件

我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进⾏数据保存时,往往不是保存成⼀个整体,⽽是独⽴成⼀个个的单位进⾏保存,这个独⽴的单位就被抽象成⽂件的概念,就类似办公桌上的⼀份份真实的⽂件⼀般。
⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数据⽽存在,我们把这部分信息可以视为⽂件的元信息。

文件路径(Path)

如何在⽂件系统中如何定位我们的⼀个唯⼀的⽂件就成为当前要解决的问题,但这难不倒计算机科学家,因为从树型结构的⻆度来看,树中的每个结点都可以被⼀条从根开始,⼀直到达的结点的路径所描述,⽽这种描述⽅式就被称为⽂件的绝对路径(absolute path)。
除了可以从根开始进⾏路径的描述,还有相对路径,先指定一个”当前目录“/ “工作目录”/"基准目录“,从当前目录出发,找到目标文件。

在实际开发中用的更多的是相对路径

文件分类

1.文本文件:是按照”文本“ / 字符串方式来理解文件内容(文本文件里面的二进制内容都是表示的字符串),进一步的,可以认为,二进制文件的内容,都是合法的字符(字符编码/普通字母/汉字)
2.二进制文件:没有上述限制,这里的内容任何数据都可以

如何判断呢?
使用记事本打开文件,如果是乱码,就是二进制文件,否者是文本文件

Java 中操作⽂件

Java 中通过 java.io.File 类来对⼀个⽂件(包括⽬录)进⾏抽象的描述。注意,有 File 对象,
并不代表真实存在该⽂件。

File 概述

我们先来看看 File 类中的常⻅属性、构造⽅法和⽅法

属性

在这里插入图片描述

构造方法

在这里插入图片描述

方法

在这里插入图片描述

代码示例

相对路径

public class Test1 {
    public static void main(String[] args) throws IOException {
//        File file = new File("D:\\java_cc\\javase\\IODemo/11.txt");
        //ctrl+D直接复制上一行内容
        File file = new File("./11.txt");
        System.out.println(file.exists());
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsoluteFile());
        System.out.println(file.getCanonicalFile());
    }
}

运行结果

true
.
11.txt
.\11.txt
D:\java_cc\javase\IODemo.\11.txt
D:\java_cc\javase\IODemo\11.txt

绝对路径

public class Test1 {
    public static void main(String[] args) throws IOException {
       File file = new File("D:\\java_cc\\javase\\IODemo/11.txt");
        //ctrl+D直接复制上一行内容

        System.out.println(file.exists());
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsoluteFile());
        System.out.println(file.getCanonicalFile());
    }
}

运行结果:

true
D:\java_cc\javase\IODemo
11.txt
D:\java_cc\javase\IODemo\11.txt
D:\java_cc\javase\IODemo\11.txt
D:\java_cc\javase\IODemo\11.txt

对比相对路径和绝对路径,get的运行结果有所差异

普通文件的创建与删除

public class Test2 {
    public static void main(String[] args) throws IOException {
        File file = new File("22.txt");//开始不存在
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile());
    }
}

运行结果

false
false
false
true
true
false
true
false

public class IODemo3 {
    public static void main(String[] args) throws InterruptedException {
        File file = new File("./test.txt");
        // boolean ret = file.delete();
        file.deleteOnExit();
        Thread.sleep(5000);
        // System.out.println(ret);
    }
}

程序运行结束后被删除

目录的创建

public class Test3 {
    public static void main(String[] args) {
        File file = new File("some-dir");
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.mkdir());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
    }
}

运行结果:

false
false
true
true
false

创建多级目录

import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File dir = new File("some-parent\\some-dir"); // some-parent 和 so
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
System.out.println(dir.mkdirs());
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
}
}

运行结果:

false
false
true
true
false

创建some-parent下的some-dir目录

文件的重命名

import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("some-file.txt"); // 要求 some-file.txt 得存在
File dest = new File("dest.txt"); // 要求 dest.txt 不存在
System.out.println(file.exists());
System.out.println(dest.exists());
System.out.println(file.renameTo(dest));
System.out.println(file.exists());
System.out.println(dest.exists());
}
}

运行结果:

true
false
true
false
true

文件的读写——数据流

流是操作系统提供的概念
Java标准库对于流进行了一系列的封装,提供了一组类来负责进行这些工作
大致分为两大类别:
1.字节流:以字节为单位进行读写,一次最少读写一个字节
代表类:InputStream(输入),OutputStream(输出)
2.字符流:以字符为单位进行读写,比如,如果utf8表示汉字,三个字节就是一个汉字,每次读写都得是以三个字节为一个单位,来进行读写,不能一次读写半个汉字
代表类:Reader(输入) Writer(输出)

InputStream概述

方法
在这里插入图片描述
说明

InputStream只是⼀个抽象类,要使⽤还需要具体的实现类。关于InputStream的实现类有很多,基
本可以认为不同的输⼊设备都可以对应⼀个InputStream类,我们现在只关⼼从⽂件中读取,所以使⽤FileInputStream

FileInputStream概述

构造方法
在这里插入图片描述

代码⽰例

⽰例1
将⽂件完全读完的两种⽅式。相⽐较⽽⾔,后⼀种的IO次数更少,性能更好。

import java.io.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "Hello" 的内容
public class Main {
	public static void main(String[] args) throws IOException {
		try (InputStream is = new FileInputStream("hello.txt")) {
		while (true) {
		int b = is.read();
			if (b == -1) {
			// 代表⽂件已经全部读完
			break;
			}
		System.out.printf("%c", b);
		}
	}
	}
}
import java.io.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "Hello" 的内容
public class Main {
	public static void main(String[] args) throws IOException {
		try (InputStream is = new FileInputStream("hello.txt")) {
			byte[] buf = new byte[1024];
			int len;
				while (true) {
				len = is.read(buf);
					if (len == -1) {
					// 代表⽂件已经全部读完
					break;
					}
				for (int i = 0; i < len; i++) {
				System.out.printf("%c", buf[i]);
				}
			}
		}
	}
}


⽰例2
这⾥我们把⽂件内容中填充中⽂看看,注意,写中⽂的时候使⽤UTF-8编码。hello.txt中填写"你好中国"
注意:这⾥我利⽤了这⼏个中⽂的UTF-8编码后⻓度刚好是3个字节和⻓度不超过1024字节的现
状,但这种⽅式并不是通⽤的

import java.io.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "你好中国" 的内容
public class Main {
	public static void main(String[] args) throws IOException {
		try (InputStream is = new FileInputStream("hello.txt")) {
			byte[] buf = new byte[1024];
			int len;
				while (true) {
				len = is.read(buf);
					if (len == -1) {
					// 代表⽂件已经全部读完
					break;
					}
				// 每次使⽤ 3 字节进⾏ utf-8 解码,得到中⽂字符
				// 利⽤ String 中的构造⽅法完成
				// 这个⽅法了解下即可,不是通⽤的解决办法
				for (int i = 0; i < len; i += 3) {
					String s = new String(buf, i, 3, "UTF-8");
					System.out.printf("%s", s);
				}
			}
		}
	}
}

利⽤Scanner进⾏字符读取

上述例⼦中,我们看到了对字符类型直接使⽤InputStream进⾏读取是⾮常⿇烦且困难的,所以,我们使⽤⼀种我们之前⽐较熟悉的类来完成该⼯作,就是Scanner类。
在这里插入图片描述

import java.io.*;
import java.util.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "你好中国" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
try (Scanner scanner = new Scanner(is, "UTF-8")) {
while (scanner.hasNext()) {
String s = scanner.next();
System.out.print(s);
}
}
}
}
}

OutputStream概述

在这里插入图片描述
在这里插入图片描述
说明
OutputStream同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件
中,所以使⽤FileOutputStream

利⽤OutputStreamWriter进⾏字符写入

import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
os.write('H');
os.write('e');
os.write('l');
os.write('l');
os.write('o');
// 不要忘记 flush
os.flush();
}
}
}
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
byte[] b = new byte[] {
(byte)'G', (byte)'o', (byte)'o', (byte)'d'
};
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
byte[] b = new byte[] {
(byte)'G', (byte)'o', (byte)'o', (byte)'d', (byte)'B', (byte)'a'
};
os.write(b, 0, 4);
// 不要忘记 flush
os.flush();
}
}
}

mport java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
String s = "Nothing";
byte[] b = s.getBytes();
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
String s = "你好中国";
byte[] b = s.getBytes("utf-8");
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}

利⽤PrintWriter找到我们熟悉的⽅法

上述,我们其实已经完成输出⼯作,但总是有所不⽅便,我们接来下将OutputStream处理下,使⽤PrintWriter类来完成输出,因为PrintWriter类中提供了我们熟悉的print/println/printf⽅法

OutputStream os = ...;
OutputStreamWriter osWriter = new OutputStreamWriter(os, "utf-8"); // 告诉
PrintWriter writer = new PrintWriter(osWriter);
// 接下来我们就可以⽅便的使⽤ writer 提供的各种⽅法了
writer.print("Hello");
writer.println("你好");
writer.printf("%d: %s\n", 1, "没什么");
// 不要忘记 flush
writer.flush();

示例:

import java.io.*;public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
try (OutputStreamWriter osWriter = new OutputStreamWriter(os, "UTF-8
try (PrintWriter writer = new PrintWriter(osWriter)) {
writer.println("我是第⼀⾏");
writer.print("我的第⼆⾏\r\n");
writer.printf("%d: 我的第三⾏\r\n", 1 + 1);
writer.flush();
}
}
}
}
}

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mang go

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值