File类
java.io.File类
- 作用:文件和目录路径名的抽象表现形式,把电脑中的文件和文件夹封装为了File类,我们可以使用File操作文件和文件夹
- 提示:File类是与系统无关的类,任何操作系统都可使用这个类
File类静态成员变量
pathSeparator : 路径分隔符
separator : 路径名称分隔符
注意:
- 操作路径不能写死,用File的静态变量来表示分隔符
- 路径不区分大写
- 路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠表示一个普通反斜杠
File类构造方法
- 1.File(String pathname) : 将指定路径名字符串转换为抽象路径名来创建一个File实例
- 2.File(String parent , String child) : 根据父子路径创建File类实例
- 3.File(File parent , String child) : 根据parent抽象路径和child路径创建File类实例
常用功能方法
- public String getAbsolutePath(): 返回File的绝对路径
- public String getPath(): 将File转换为路径名字符创
- public String getName(): 返回由此File表示的文件或目录的名称
- public long length(): 返回文件的长度(大小,以字节为单位)(toString方法就是调用此方法)
- public boolean exists(): 此File表示的文件或者目录是否存在
- public boolean isDirector(): 此File表示的是否为目录
- public boolean isFile(): 此File表示的是否是文件
isDirector 和 isFile 方法使用的前提是必须File表示的文件路径是存在的,否则都返回false,如果路径存在,两个方法返回值正好相反
public class Demo01File {
public static void main(String[] args) {
String p = File.pathSeparator;
// System.out.println(p); // linux是 : , window是 ;
String s = File.separator;
// System.out.println(s); // linux 是 / , window 是 \
File f = new File("/Users/jiatengda/Desktop/basic-code/a.txt");
System.out.println(f); // /Users/jiatengda/Desktop/basic-code/a.txt
File f2 = new File("C" , "b.md");
System.out.println(f2); // C/b.md
System.out.println(f.getAbsoluteFile());///Users/jiatengda/Desktop/basic-code/a.txt
System.out.println(f.getPath()); // /Users/jiatengda/Desktop/basic-code/a.txt
System.out.println(f.toString()); // /Users/jiatengda/Desktop/basic-code/a.txt
System.out.println(f.getName()); //a.txt
System.out.println(f.length()); // 0 无此文件也是0
}
}
IO流
- I(input): 输入(读取)
- O(output): 输出(写入)
- 流: 数据(字符,字节) => 1 字符 = 2 字节 = 8二进制位
字节流
- InputStream: 字节输入流
- OutputStream : 字节输出流
一切皆为字节
- 电脑中存储的任意文件都是以二进制形式保存,传输时一样如此,字节流可以传输任意文件数据,底层传输的始终是二进制数据.
java.io.OutputStream : 此抽象类是所有表示输出字节流的超类
共性方法
- public void close():关闭输出流并释放与此流相关的任何系统资源
- public void flash():刷新此输出流并强制任何缓冲的字节被写出
- public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流
- public void write(byte[] b , int off , int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
- public abstract void write(int b): 将指定的字节输出流
java.io.FileOutputStream extends OutputStream : 文件字节输出流
- 作用: 把内存中的数据写入到硬盘的文件中
- 写入数据的原理(内存 -> 硬盘):
- java程序->JVM(java虚拟机)->OS(操作系统)->OS调用写数据的方法->把数据写入到文件中
文件字节输出流使用步骤
public class Demo04File { public static void main(String[] args) throws IOException { // 1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地 FileOutputStream fos = new FileOutputStream("a.txt"); // 2.调用FileOutputStream对象中的write方法,把数据写入到文件中 fos.write(97); // 3.释放资源(流的使用会占用一定内存,使用完毕要关闭掉,提高程序效率) fos.close(); } }
InputStreamFile 输入流
- 此抽象类表示字节输入流的所有类的超类
共性方法
int read(): 从输入流中读取下一个字节
int read(byte[] b) : 从输入流中读取一定量的字节,并将其存在缓冲区b中
void close() : 关闭此输入流并释放相关的所有资源
实现类 java.io.FileInputStream extends InputStream
- 文件输入流,读取文件(把硬盘中的数据,读取到内存中使用)
读取数据原理:java程序 -> jvm -> os -> os读取数据的方法 -> 读取文件
字节输入流的使用步骤:
- 使用字节流读取中文字符时的问题:会产生乱码的问题 => 使用字符流解决
public class Demo05FileInput { public static void main(String[] args) throws IOException { // 1. 创建FileInputStream对象,构造方法中绑定要读取的数据源 FileInputStream fis = new FileInputStream("a.txt"); // 2. 使用FileInputStream对象中的方法read读取文件 // int read() 读取一个字节并返回,读到最后返回-1 int len = 0; // 记录读取到的字节 while ((len = fis.read() )!=-1){ // 条件判断 // 1. fis.read()读取一个字节 // 2. len = fis.read(): 读取到的字节赋值给len // 3. 与-1进行判断 System.out.println((char) len); } //3. 释放资源 fis.close(); } }
一次读取多个字节
- int read(byte[] b) : 从输入流中读取一定量的字节,并将其存在缓冲区b中
参数byte[]的作用
- 起到缓冲作用,存储每次读取到的多个字节,
- 数组的长度一般把其定义为1024(1kb)或者1024的整数倍
- 返回值int是每次读取有效字节的个数
public class Demo06FileInput {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
byte[] bytes = new byte[1024]; // 存储读取到的多个字节
int len = 0;
while ((len = fis.read(bytes)) !=-1){
System.out.println(new String(bytes,0,len));
}
fis.close();
}
}
复制文件案例
package cn.jiatengda.day09.demo08; // 文件复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
*
- 创建字节输入流对象,构造方法中绑定要读取的数据源
- 创建字节输出流对象,构造方法中绑定要写入的目的地
- 输入流对象read,输出流write
- 释放资源
- /
public class Demo07File {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(“/Users/jiatengda/Desktop/LiQuan/孟炜浩简历.docx”);
FileOutputStream fos = new FileOutputStream(“/Users/jiatengda/Desktop/Project/1.docx”);
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes))!= -1){
fos.write(bytes,0,len);
}
// 先关闭写入流,后关闭读取流
fos.close();
fis.close();
}
}
> 字符流
> - Reader: 字符输入流
> - Writer: 字符输出流
> java.io.Reader: 字符输入流,是字符输入流最顶层父类
> - 是一个抽象类,定义了共性的成员方法:
> - 1. int read() : 读取单个字符并返回
> - 2. int read(char[] chars) : 读取多个字符,并读入数组
> - 3. void close() : 关闭流并释放资源
> java.io.FileReader extends InputStreamReader extends Reader:
> - 作用:把硬盘文件中的数据以字符的方式读取到内存中
> 使用步骤
```java
public class Demo01Reader {
public static void main(String[] args) throws IOException {
// 1. 创建一个FileReader对象
FileReader fr = new FileReader("a.txt");
// 2. 调用read方法读取
// int len = 0 ;
// while ((len = fr.read())!=-1){
// System.out.print((char)len);
// }
// 2. 利用缓冲数组多个字符读取
char[] chars = new char[1024];
int len = 0;
while ((len = fr.read(chars))!=-1){
/**
* String(char[] value) : 把字符数组转化为字符串
* String(char[] value , int offset , int length) : 将指定位置和长度的字符数组转换为字符串
*/
System.out.println(new String(chars,0,len));
}
// 3. 释放资源
fr.close();
}
}
java.io.Writer: 抽象类,字符输出流最顶层的超类
- 共性成员方法:
- void write(int c) :
- void writer(char[] cbuf) 写入字符数组
- abstract void writer(char[] cbuf , int off , int len ) 写入数组的一部分,
- write (String str) 写入字符串
- write (String str , int off , int len) 写入字符串一部分
- void flush() 刷新该流的缓冲
- void close() 关闭此流,但是要先刷新它
java.io.FileWriter extends OutputStreamWriter extends Writer : 文件字符输出流,把内存中的数据写入到文件中
使用步骤
public class Demo01Writer { public static void main(String[] args) throws IOException { // 1. 创建一个FileWriter对象 FileWriter fw = new FileWriter("a.txt"); // 2. 调用write方法写入字符 fw.write(97); // 3. 使用FileWriter中的方法flush , 把内存缓冲区中的内容,刷新到文件中 fw.flush(); fw.write(98); // 4. 释放资源(会先把内存区中的数据刷新到文件中 ) fw.close(); } }
flush 和 close的区别
- flush :刷新缓冲区,流可以继续使用
- close : 刷新缓冲区,然后通知系统释放资源,流对象不能继续使用
续写和换行
- FileWriter(String filename ,boolean append)
- FileWriter(File file ,boolean append)
- 换行 macOS: \r linux: \n window: \r \n
缓冲区buffered
缓冲流: 基本流是一个一个的读,缓冲流会增加一个缓冲区,把字节/字符存到数组中,然后在返回
子节缓冲输出流: 字节输出流的方法可用
- 构造方法
- BufferedOutputStream(OutputStream os)
- BufferedOutputStream(OutputStream os , int size)
使用步骤
- 字节缓冲输入流类似
public class Demo01Buffered { public static void main(String[] args) throws IOException { // 1.创建字节输出流(FileOutputStream)对象,构造方法中绑定要输出的目的地 FileOutputStream fos = new FileOutputStream("c.txt"); // 2.创建BufferedInputStream对象,构造方法传递FileOutputStream对象,提高效率 BufferedOutputStream bos = new BufferedOutputStream(fos); // 3.使用BufferedInputStream对象中的方法write,把数据写入到内部缓冲区中 bos.write("把数据写入到缓冲区中".getBytes()); //4.使用BufferedInputStream对象中的方法flush,把内部缓冲区的数据,刷新到文件中 bos.flush(); // 可不写 // 5.释放资源 bos.close(); } }
字符缓冲区
- BufferedWriter extends Writer
- 特有成员方法: void newLine():写入一个行分隔符,根据系统写换行符
- BufferedReader extends Reader
- 特有成员方法String readline() : 读取一行文本。行的终止符号 \r \n \r\n
- 返回值 : 返回一行,如果达到末尾,返回null
public class Demo01BufferedWriter {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
for (int i = 0; i < 10; i++) {
bw.write("贾腾达");
bw.newLine();
}
bw.flush();
bw.close();
}
}
编码(转化流)
ascii 编码: 美国编码表
gbxxx: 中文编码表,一般中文两个字节表示
unicode : 万国码,utf-8最为常见。一般中文三个字节表示,
编码不同引出的问题
IDE一般是utf8编码,但是读取系统文件是默认gbk编码,或出现乱码问题
转换流解决编码问题
转换流可以指定编码表
- InputStreamReader
- OutputStreamWriter
转换流原理
转换流的使用
package cn.jiatengda.day09.demo10;
import java.io.*;
/**
* OutputStreamWriter extends Writer
* 作用: 字符流通向字节流的桥梁,把字符转换为字节,把能看懂的转换为看不懂的
* 拥有父类的共性方法
*
* 构造方法:
* OutputStreamWriter(OutputStream out) : 使用默认字节编码
* OutputStreamWriter(OutputStream out , String charsetName) 使用指定字节编码
* 参数:
* OutputStream out : 字节输出流,把转换的字节写入指定位置
* String charsetName : 指定编码表名称,不区分大小写,不指定默认使用utf-8
* 使用步骤:
* 1. 创建OutputStreamWriter对象,构造方法中传入字节输出流和指定的编码表名称
* 2. 使用OutputStreamWriter对象中的方法write,把字符转换为字节存储在缓冲区中(编码)
* 3. 使用OutputStreamWriter对象中的flush方法,把内存缓冲去中的字节刷新到文件中
* 4. 释放资源
*
* ### InputStreamReader extends Reader
* 作用: 字节流向字符的桥梁,把字节转换为字符,把看不懂的转换为能看懂的
* 拥有父类的共性方法
*
* 构造方法:
* InputStreamReader(InputStream)
* InputStreamReader(InputStream,String charsetName)
*
* 使用步骤:
* 1. 创建InputStreamReader对象,构造方法中传入字节输入流和指定的编码表名称
* 2. 使用InputStreamReader对象中的read方法,读取文件
* 3. 释放资源
* 注意:
* 1. 构造方法中指定的编码表名称和文件的编码必须相同,否则会乱码
*
*/
public class Demo01InputFR {
public static void main(String[] args) throws IOException {
write_utf_8();
read_utf_8();
}
// 读取utf-8的文件
private static void read_utf_8() throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("e.txt"),"utf-8");
int len = 0;
while ((len = isr.read())!=-1){
System.out.println((char)len);
}
isr.close();
}
// 使用转换流OutputStreamWriter写utf-8格式的文件
private static void write_utf_8() throws IOException {
// 1. 创建OutputStreamWriter对象,构造方法中传入字节输入流和指定的编码表名称
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("e.txt"),"utf-8");
// 2. 使用OutputStreamWriter对象中的方法write,把字符转换为字节存储在缓冲区中(编码)
osw.write("你好啊,IDEA");
osw.flush();
osw.close();
}
}
序列化和反序列化
对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化。
- ObjectOutputStream: 对象序列化流 => writeObject()
- 特有成员方法: void writeObject(object obj) : 把指定对象写入ObjectOutputStream
- ObjectInputStream: 对象反序列化流 => readObject()
- 特有成员方法: Object readObject() 从ObjectInoutStream读取对象
- 使用前提
- 类必须实现Serializable接口
- 必须存在对应的class文件
public class Demo01ObjStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// //1. 创建ObjectOutputStream对象,参数传递字节输出流
// ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
// // 2. 使用ObjectOutputStream对象方法writeObject,把对象写入文件中
// oos.writeObject(new Person("贾腾达",18)); // NotSerializableException
// // 3. 释放资源
// oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
Object obj = ois.readObject();
ois.close();
System.out.println(obj);
Person p = (Person) obj ;
System.out.println(p.getAge() + p.getName());
}
}
Person 类
package cn.jiatengda.day09.demo10;
import java.io.Serializable;
/**
* Serializable接口,也叫标记性接口
* 要进行序列化和反序列化的类必须实现此接口,会给类添加一个标记
* 当我们进行序列化和反序列化的时候,就会检测这个类上是否有这个标记,如果有就可以序列化或者反序列化,否则就会跑出NotSerializable异常
* 比如去市场卖肉,肉上有一个蓝色的章,上面有检测合格,有这个才可以放心购买。
*/
public class Person implements Serializable {
private String name ;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
transient关键字: 瞬态关键字
- 被transient关键字修饰的成员变量不能被序列化
- 当不想成员变量被序列化可以用此关键字修饰
- 没有static的含义,而且不能被序列化
static关键字: 静态关键字
- 优先于非静态加载到内存中(优先于对象进入到内存中)
- 被static修饰的成员变量是不能被序列化的,序列化的都是对象
异常: 找不到class文件的原理
- 可以给可序列化类声明serialVersionUID的字段,
- 字段固定格式 修饰符 static final long serialVersionUID = xxx;
打印流
java.io.PrintStream extends OutputStream: 打印流
- 作用: 为其他流增加了功能,使他们能够方便的打印各种数据值表示形式
特点
- 只负责数据的输出,不负责数据的独处
- 和其他流不一样 ,永远不会抛出IOException
- 有特有的方法,print,println,参数可以是任意类型值
构造方法
PrintStream(File file) : 输出的目的地是一个 文件
PrintStream(OutputStream out) : 输出的目的地是一个字节输出流
PrintStream(String filename) : 输出的目的地是一个文件路径
public class Demo01StreamConsole { public static void main(String[] args) throws FileNotFoundException { PrintStream ps = new PrintStream("f.txt"); ps.write(97);//a ps.println(97);//97 ps.println("a");//a ps.println("你好");//你好 ps.println(true);//true ps.close(); // 修改输出目的地 System.setOut(ps); } }
Stram流 && 常用函数接口
常用函数接口
- Supplier接口: Supplier
: T get() , 生产接口 - Consumer接口: Consumer
: void accept(T t) 消费接口 - Predicate接口: Predicate
: 对某种类型的数据进行判断,结果返回布尔值
- 唯一方法: boolean test(T t)
- Function接口: Function<T,R>: 根据一个类型的数据得到另外一个类型的数据
- 唯一抽象方法: R apply(T t)
- 默认方法: andThen(): 进行组合操作
public class Demo02Func {
public static void main(String[] args) {
// boolean bol = checkString("abcd",(String str)->str.length() > 5);
// System.out.println(bol);
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三丰");
list.add("张天");
list.add("赵地");
list.stream().filter(name -> name.startsWith("张")) // 参数为Predicate接口
.filter(name -> name.length()==3)
.forEach(name -> System.out.println(name)); // 参数为Consumer接口
}
private static boolean checkString(String str , Predicate<String> pre) {
return pre.test(str);
}
}
Stram流
常用方法:
- void forEach(Consumer<? super T> action)
- 作用: 用来遍历流中数据
- 是一个终结方法,调用完了后不能在调用流中的其他方法
- Stream
filter(Predicate<? super T> predicate) - 作用: 过滤流中的数据并返回过滤后的数据
- R Stream
map(Function <? super T , ? extends R> mapper) - 作用: 可以将当前T类型数据转换为R类型数据
- long count()
- 作用: 统计流中的元素个数
- 是一个终结方法,不能再继续调用流中的其他方法
- Stream
limit(long maxSize); (从0截取到maxSize) - 作用: 对当前流进行截取,如果流长度大于参数,就截取,否则不进行任何操作
- 是一个延迟方法,只对流中的数据进行截取,返回新的流,可以继续调取流的方法
- Stream
skip(long n); (从n截取到末尾) - 作用: 跳过n个流中元素,如果n大于流的长度,则返回一个空的流
- static
Stream concat(Stream<? extends T> a , Stream<? extends T>b) - 作用: 将两个流合并成一个流
- 注意:
- Stream流是管道流, 只能被消费一次,使用完之后就会关闭,不能再次使用
public class Demo01Streanm {
public static void main(String[] args) {
// 把集合转换成Stream流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();
Map<String,String> map = new HashMap<>();
Set<String> keySet = map.keySet();
Stream<String> stream3 = keySet.stream();
Collection<String> values = map.values();
Stream<String> stream4 = values.stream();
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream5 = entries.stream();
// 把数组转换为流
Stream<Integer> stream6 = Stream.of(1,2,3,4,5,6,7,8,9,0);
Integer[] arr = {1,2,3,4,5,6};
Stream<Integer> stream7 = Stream.of(arr);
stream7.forEach(i -> System.out.println(i));
}
}