目前存储数据都是在内存中进行,在内存中存储的数据是用来处理、修改、运算的,不能长久保存。
File类可以定位文件:进行删除、获取文本本身信息等操作但是不能读写文件内容
读写文件数据,IO流技术可以对硬盘中的文件进行读写
File类
java.io.File类
文件和目录路径名的抽象表示形式
Java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作
我们可以使用File类的方法
创建一个文件/文件夹
删除文件/文件夹
获取文件/文件夹
判断文件/文件夹是否存在
对文件夹进行遍历
获取文件的大小
File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法
重点:file:文件 directory:文件夹/目录 path:路径
File类的静态成员变量
static String pathSeparator
与系统有关的路径分隔符,为了方便,它被表示为一个字符串
static char pathSeparatorChar
与系统有关的路径分割符
static String separator
与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串
static char separatorChar
与系统有关的默认名称分隔符
注意:操作路径,不能写死了,应该以==“+File.separator+”==代替正反斜杠
windows:C:\develop\a\a.txt
linux:C:/develop/a/a.txt
"C:"+File.separator+"develop"+File.separator+"a"+File.separator+"a.txt"
public class Demo01File {
public static void main(String[] args) {
//static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串
String pathSeparator = File.pathSeparator;
System.out.println(pathSeparator);//;路径分隔符,windows分号Linux为冒号
//static String separator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串
String separator = File.separator;
System.out.println(separator);//\文件名称分隔符,windows反斜杠linux为正斜杠
}
绝对路径和相对路径
路径:
绝对路径:完整的路径
以盘符(C、D)开始的路径 E:\soft\IDEA
相对路径:简化的路径
相对指的是相对于当前项目的根目录
如果使用当前项目的根目录,可以简化书写
E:\soft\IDEA–>IDEA(可以省略项目的根目录)
注意:1、路径是不区分大小写的
2、路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠
File类的构造方法
File(String pathname)
通过将给定路径名字字符串转换为抽象路径名来创建一个新File实例
File(String parent,String child)
根据parent路径名字符串和child路径名字符创建一个新的File实例
File(File parent,String child)
根据parent抽象路径和child路径名字符串创建也给新的File实例
File对象可以定位文件和文件夹
File封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的。
public class Demo02File {
public static void main(String[] args) {
//File类的构造方法
show01();
show02("c:\\","a.txt");
show03();
}
//File(String pathname)通过将给定路径名字字符串转换为抽象路径名来创建一个新File实例
//参数:String pathname:字符串的路径
//路径可以是以文件结尾,也可以是以文件夹结尾
//路径可以是相对路径,也可以是绝对路径
//路径可以是存在的,也可以是不存在的
//创建File对象,只是把字符串路径封装为File对象,不考虑路径的真假情况
private static void show01() {
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");//绝对的文件
System.out.println(f1);//D:\java\ceshi\day01\a.txt 重写了toSting方法
File f2 = new File("D:\\java\\ceshi\\day01\\xiaohaha");//绝对的文件夹
System.out.println(f2);
File f3 = new File("b.txt");//相对路径
System.out.println(f3);
}
//File(String parent,String child)根据parent路径名字符串和child路径名字符创建一个新的File实例
//参数:把路径分为了两部分
// String parent:父路径
// Strign child:子路径
//好处:父路径和子路径,可以单独书写,使用起来非常灵活,父路径和子路径都可以变化
private static void show02(String parent,String child) {
File file = new File(parent,child);
System.out.println(file);//c:\a.txt
}
//File(File parent,String child)根据parent抽象路径和child路径名字符串创建也给新的File实例
//参数:把路径分成了两部分
// String parent:父路径
// String child:子路径
//好处:路径可以随时变化,父路径是File类型,可以使用File的方法对路径进行一些操作,再使用路径创建都行
private static void show03() {
File parent = new File("c:\\");
File file = new File(parent,"hello.java");//可以使用File的方法对路径进行一些操作
System.out.println(file);//c:\hello.java
}
}
File类获取功能的方法
public String getAbsolutePath()
:返回File的绝对路径名字符串
public String getPath()
:将此file转换为路径名字符串
public String getName()
:返回由此file表示的文件或目录的名称
public long length()
:返回由此file表示的文件长度
public long lastModified()
返回文件最后修改的时间毫秒值
public class Demo03File {
public static void main(String[] args) {
show01();
show02();
show03();
show04();
}
//public String getAbsolutePath():返回File的绝对路径名字符串
//获取的是构造方法中传递的路径
//无论路径是绝对的还是相对的,getAbsolutePath()方法返回的都是绝对路径
private static void show01() {
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");
String absolutePath1 = f1.getAbsolutePath();
System.out.println(absolutePath1);//D:\java\ceshi\day01\a.txt
File f2 = new File("a.txt");
String absolutePath2 = f2.getAbsolutePath();
System.out.println(absolutePath2);//D:\java\zgDaren\a.txt
}
//public String getPath():将此file转换为路径名字符串
//获取的是构造方法中传递的路径
//toSting调用的也就是getPath方法
//源码:public String toString(){
// return getPath();
// }
private static void show02() {
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");
File f2 = new File("a.txt");
String path1 = f1.getPath();
System.out.println(path1);//D:\java\ceshi\day01\a.txt
String path2 = f2.getPath();
System.out.println(path2);//a.txt
System.out.println(f1);//D:\java\ceshi\day01\a.txt 重写了toString方法
System.out.println(f1.toString());//D:\java\ceshi\day01\a.txt
}
//public String getName():返回由此file表示的文件或目录的名称
//获取的就是构造方法传递路径的结尾部分(文件/文件夹)
private static void show03() {
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");
String name1 = f1.getName();
System.out.println(name1);//a.txt
File f2 = new File("D:\\java\\ceshi\\day01");
String name2 = f2.getName();
System.out.println(name2);//day01
}
//public long length():返回由此file表示的文件长度
//获取的是构造方法指定的文件大小,以字节为单位
//注意:问价夹是没有大小概念的,不能获取文价夹的大小
// 如果构造方法中给出的路径不存在,那么length方法返回的值为0
private static void show04() {
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");
long l1 = f1.length();
System.out.println(l1);//28
}
}
File类判断功能的方法
public boolean exists()
:此File表示的文件夹或目录是否实际存在
public boolean isDirectory()
:此File表示的是否为目录
public boolean isFile()
:此File表示的是否为文件
public class Demo04File {
public static void main(String[] args) {
show01();
show02();
}
//public boolean exists():此File表示的文件夹或目录是否实际存在
//用于判断构造方法中的路径是否存在
//存在返回true 不存在返回false
private static void show01() {
//判断存在的绝对路径
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");
boolean e1 = f1.exists();
System.out.println(e1);//true
//判断不存在的绝对路径
File f2 = new File("D:\\java\\ceshi\\day01\\b.txt");
boolean e2 = f2.exists();
System.out.println(e2);//false
//判断存在的相对路径
File f3 = new File("a.txt");
System.out.println(f3.exists());//true
}
//public boolean isDirectory():此File表示的是否为目录
// 用于判断构造方法中给定的路径是否以文件夹结尾
// 是:true 否:false
//public boolean isFile():此File表示的是否为文件
// 用于判断构造方法中给定的路径是否以文件结尾
// 是:true 否:false
//注意:电脑的硬盘中只有文件/文件夹,两个方法是互斥
// 这两个方法使用前提:路径必须是存在的,否则都返回false
private static void show02() {
File f1 = new File("D:\\java\\ceshi\\day01\\a.txt");
System.out.println(f1.isDirectory());//false
System.out.println(f1.isFile());//false
}
}
File类创建删除功能的方法
public boolean createNewFiLe()
:当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete()
:删除由此FiLe表示的文件或目录。
delete方法默认只能删除文件和空文件夹,delete方法直接删除不走回收站
public boolean mkdir()
:创建由此FiLe表示的目录。
public boolean mkdirs()
:创建由此FiLe表示的目录,包括任何必需但不存在的父目录。
public class Demo05File {
public static void main(String[] args) throws IOException {
show01();
show02();
show03();
}
//public boolean createNewFiLe():当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
//创建问价的路径和名称再构造方法中给出(构造方法的参数)
//返回值:boolean true:文件不存在,创建文件,返回true
// false:文件存在,不会创建,返回false
//注意:1、此方法只能创建文件,不能创建文件夹
// 2、创建文件的路径必须存在,否则会抛出异常
private static void show01() throws IOException {
//绝对路径创建
File f1 = new File("D:\\java\\ceshi\\day01\\1.txt");
boolean b1 = f1.createNewFile();
System.out.println(b1);//true成功创建了1.txt文件
//相对路径创建
File f2 = new File("2.txt");
System.out.println(f2.createNewFile());
}
//public boolean mkdir() :创建由此FiLe表示的目录。只能创建单级文件夹
//public boolean mkdirs():创建由此FiLe表示的自录,包括任何必需但不存在的父目录。既可以创建单级文件夹也可创建多级空
//创建文件夹的路径和名称再构造方法中给出(构造方法的参数)
//返回值:boolean true:文件夹不存在,创建文件,返回true
// false:文件夹存在,不会创建,返回false;构造方法中给出的路径不存在也返回false
//注意:此方法只能创建文件夹,不能创建文件
private static void show02() {
//创建单级文件夹
File f1 = new File("D:\\java\\ceshi\\day01\\aaa");
boolean b1 = f1.mkdir();
System.out.println(b1);//true 创建了一个aaa的文件夹
//创建多级文件夹
File f2 = new File("D:\\java\\ceshi\\day01\\aaa\\bbb\\ccc");
boolean b2 = f2.mkdirs();
System.out.println(b2);//true创建多级文件夹
}
//public boolean delete():删除由此FiLe表示的文件或目录。
//此方法,可以删除构造方法路径中给出的文件/文件夹
//返回值:boolean
// true:文件/文件夹删除成功,返回true
// false:文件夹中有内容,不会删除返回false,构造方法中路径不存在false
//注意:delete方法是直接在硬盘删除文件/文件夹,不走回收站,删除要谨慎
private static void show03() {
File f1 = new File("2.txt");
System.out.println(f1.delete());//true成功删除文件2.txt
File f2 = new File("D:\\java\\ceshi\\day01\\aaa\\bbb");
System.out.println(f2.delete());//false,因为bbb文件夹中还有文件夹ccc
File f3 = new File("D:\\java\\ceshi\\day01\\aaa\\ddd");
System.out.println(f3.delete());//false,没有ddd文件夹
}
}
FiLe类遍历(文件夹)目录功能
public String[ ] list()
:返回一个String数组,表示该FiLe目录中的所有子文件或目录。
public File[ ] listFiLes()
:返回一个FiLe数组,表示该FiLe目录中的所有的子文件或目录。
注意:
List方法和ListFiles方法遍历的是构造方法中给出的目录
如果构造方法中给出的目录的路径不存在,会抛出空指针异常
如果构造方法中给出的路径不是一个目录,也会抛出空指针异常
listFiles方法注意事项:
当调用者不存在时,返回null
当调用者是一个文件时,返回null
当调用者是一个空文件夹时,返回一个长度为0的数组
当调用者是一个有内容的文件夹时,将里面的所有文件和文件夹的路径放到File数组中返回
当调用者是一个有隐藏文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
当调用者是一个需要权限才等进入的文件夹时,返回null。
public class Demo06File {
public static void main(String[] args) {
show01();
show02();
}
//public String[ ] list():返回一个String数组,表示该FiLe目录中的所有子文件或目录。
//遍历构造方法中给出的目录,会获取目录中所有文件/文件夹的名称,把获取到的多个名称存储到一个String类型的数组中
//也可获取到隐藏的文件夹
private static void show01() {
File f1 = new File("D:\\java\\ceshi\\day01");
String[] arr = f1.list();
for (String fileName:arr){
System.out.println(fileName);//1.txt a.txt aaa
}
}
//public File[ ] listFiLes():返回一个FiLe数组,表示该FiLe目录中的所有的子文件或目录。
//遍历构造方法中给出的目录,会获取目录中所有文件/文件夹,把文件/文件夹封装为File对象,多个File对象存储到File数组中
private static void show02() {
File f1 = new File("D:\\java\\ceshi\\day01");
File[] arr = f1.listFiles();
for (File fileName:arr){
System.out.println(fileName);//D:\java\ceshi\day01\1.txt D:\java\ceshi\day01\a.txt D:\java\ceshi\day01\aaa
}
}
}
递归
概念
方法直接调用自己或者间接调用自己的形式称为方法的递归(recursion)。
递归作为一种算法在设计语言中广泛使用。
递归的形式
直接递归:方法自己调用自己
间接递归:方法调用其他方法,其他方法又回调方法自己。
递归的分类
递归分为两种,直接递归和间接递归
直接递归称为方法自身调用自己
间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法
注意事项
递归一定要有条件限制,保证递归能够停止下来,否则会发生栈内存溢出
在递归中虽然有限定条件,但是递归次数不能太多,否则也会发生栈内存溢出
构造方法:禁止递归
递归的使用前提: 当调用方法的时候,方法的主体不变,每次调用方法的参数不同,可以使用递归
public class Demo01Recurison {
public static void main(String[] args) {
a();
b(1);
}
//递归一定要有条件限制,保证递归能够停止下来,否则会发生栈内存溢出
private static void a() {
System.out.println("a方法");
a();
}
//在递归中虽然有限定条件,但是递归次数不能太多,否则也会发生栈内存溢出
private static void b(int i) {
System.out.println(i);
if (i==1000){
return;//结束方法
}
b(++i);
}
//构造方法不能递归
//编译报错:构造方法是创建对象使用的,一直递归会导致内存中有无数个对象,直接编译报错
//
public Demo01Recurison(){
//Demo01Recurison();
}
}
使用递归计算1-n之间的和
public class Demo02Recurison {
public static void main(String[] args) {
int s = sum(3);
System.out.println(s);//6
}
//定义一个方法,使用递归计算1-n之间的和
//1+2+3+...+n
//n+(n-1)+(n-2)+...+1
//最大值n,最小值1
//使用递归必须明确:1、递归的结束条件 获取到1的时候结束
// 2、递归的目的:获取到下一个被加的数字(n-1)
public static int sum(int n){
//获取到1的时候结束
if(n==1){
return 1;
}
//获取下一个被加的数组(n-1)
return n + sum(n-1);
}
}
递归求阶乘
public class Demo03Recurison {
public static void main(String[] args) {
int h = cJ(5);
System.out.println(h);
}
//定义方法使用递归计算阶乘
//5! = 5*(5-1)*(5-2)*(5-3)*(5-4)
//递归结束的条件:获取到1的时候结束
//递归的目的:获取到下一个被乘的数字(n-1)
public static int cJ(int n){
//获取到1的时候结束
if (n==1){
return 1;
}
//获取到下一个被乘的数字(n-1)
return n * cJ(n-1);
}
}
打印多级目录
//递归打印多级目录
public class Demo04Recurison {
public static void main(String[] args) {
File file = new File("D:\\java\\ceshi\\day01");
getAllFile(file);
}
//定义一个方法,参数传递File类型目录
//方法中对目录进行遍历
public static void getAllFile(File dir){
System.out.println(dir);//输出打印文件夹名称
File[] files = dir.listFiles();
for (File f : files) {
//对遍历得到的File对象f进行判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用getAllFile方法即可
getAllFile(f);
}else {
//f是一个文件,直接打印即可
System.out.println(f);
}
}
}
}
文件搜索
//递归打印多级目录
public class Demo05Recurison {
public static void main(String[] args) {
File file = new File("D:\\java\\ceshi\\day01");
getAllFile(file);
}
//定义一个方法,参数传递File类型目录
//方法中对目录进行遍历
public static void getAllFile(File dir){
//System.out.println(dir);//输出打印文件夹名称
File[] files = dir.listFiles();
for (File f : files) {
//对遍历得到的File对象F进项判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用getAllFile方法即可
getAllFile(f);
}else {
//f是一个文件,直接打印即可
//只要.java结尾的文件
//1、把File对象f,转换为字符串对象
//String name = f.getName();//abc.java
//String path = f.getPath();//D:\\ceshi\\day01\\abc.java
String s = f.toString();//D:\\ceshi\\day01\\abc.java
//把字符串转换为小写
s = s.toLowerCase(Locale.ROOT);
//2、调用String类中的方法endsWith判断字符串是否是以.java结尾
boolean b = s.endsWith(".java");
//3、如果是以.java结尾的文件则输出
if (b){
System.out.println(f);
}
}
}
}
}
过滤器
使用过滤器来是实现
在File类中有两个和ListFiles重载的方法,方法的参数传递的就是过滤器
File[] listFiles(FileFilter filter)
java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器
作用:用来过滤文件(File对象)
抽象方法:用来过滤文件的方法
boolean accept(File pathname)
测试指定抽象路径名是否应该包含在某个路径名列表中
参数:File pathname:使用ListFiles方法遍历目录,得到的每一个文件对象
File[] listFiles(FilenameFilter filter)
java.io.FilenameFiles接口:实现此接口的类实例可用于过滤器文件名
作用:用于过滤文件名称
抽象方法:用来过滤文件的方法
boolean accept(File dir,String name)
测试指定文件是否应该包含在某一文件列表中
参数:File dir:构造方法中传递的被遍历的目录
String name:使用ListFiles方法遍历目录,获取的每一个文件/文件夹名称
注意:两个过滤器接口是没有实现类的,需要我们自己写实现类,重写过滤器的方法accept,在方法中自己定义过滤的规则
使用第一种过滤器
主方法
public class Demo01Filter {
public static void main(String[] args) {
File file = new File("D:\\java\\ceshi\\day01");
getAllFile(file);
}
//定义一个方法,参数传递File类型目录
//方法中对目录进行遍历
public static void getAllFile(File dir){
File[] files = dir.listFiles(new FileFiterImpl());//传递过滤器对象
for (File f : files) {
//对遍历得到的File对象F进项判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用getAllFile方法即可
getAllFile(f);
}else {
//f是一个文件,直接打印即可
System.out.println(f);
}
}
}
}
使用匿名内部类
public class Demo02Filter {
public static void main(String[] args) {
File file = new File("D:\\java\\ceshi\\day01");
getAllFile(file);
}
//定义一个方法,参数传递File类型目录
//方法中对目录进行遍历
public static void getAllFile(File dir){
//传递过滤器对象,使用匿名内部类传递
File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
//过滤规则,pathname是文件夹或者是.java结尾的文件返回true
return pathname.isDirectory() || pathname.getName().toLowerCase(Locale.ROOT).endsWith(".java");
}
});
for (File f : files) {
//对遍历得到的File对象F进项判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用getAllFile方法即可
getAllFile(f);
}else {
//f是一个文件,直接打印即可
System.out.println(f);
}
}
}
}
重写accept方法
//创建过滤器FileFilter的实现类,重写过滤方法accept,定义过滤规则
public class FileFiterImpl implements FileFilter {
@Override
public boolean accept(File pathname) {
//在此方法中,判断File对象是否是以.java结尾
//是就返回true,不是就返回false
//如果pathname是一个文件夹,返回true,继续编辑这个文件夹
if (pathname.isDirectory()){
return true;//返回true后会把文件夹也放在File数组中
}
return pathname.getName().toLowerCase(Locale.ROOT).endsWith(".java");
}
}
为什么要重写accept方法的原理
在accept方法中判断传递的文件是否以.java结尾
使用第二种过滤器
public class Demo02Filter {
public static void main(String[] args) {
File file = new File("D:\\java\\ceshi\\day01");
getAllFile(file);
}
//定义一个方法,参数传递File类型目录
//方法中对目录进行遍历
public static void getAllFile(File dir){
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//过滤规则,pathname是文件夹或者是.java结尾的文件返回true
return new File(dir,name).isDirectory() || name.toLowerCase(Locale.ROOT).endsWith(".java");
}
});
for (File f : files) {
//对遍历得到的File对象F进项判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用getAllFile方法即可
getAllFile(f);
}else {
//f是一个文件,直接打印即可
System.out.println(f);
}
}
}
}
使用Lambda表达式优化匿名内部类
public class Demo02Filter {
public static void main(String[] args) {
File file = new File("D:\\java\\ceshi\\day01");
getAllFile(file);
}
//定义一个方法,参数传递File类型目录
//方法中对目录进行遍历
public static void getAllFile(File dir){
//使用Lambda表达式优化匿名内部类(接口中只有一个抽象方法)
File[] files = dir.listFiles((File d, String name)->{
//过滤规则,pathname是文件夹或者是.java结尾的文件返回true
return new File(d,name).isDirectory() || name.toLowerCase(Locale.ROOT).endsWith(".java");
});
for (File f : files) {
//对遍历得到的File对象F进项判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用getAllFile方法即可
getAllFile(f);
}else {
//f是一个文件,直接打印即可
System.out.println(f);
}
}
}
}
字符集
String编码
byte[] getBytes() 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中。
byte[] getBytes(String charsetName) 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中。
String解码
String(byte[] bytes)通过使用平台的默认字符集解码指定的字节数组来构造新的String。
String(byte[] bytes,String charsetName)通过指定的字符集解码指定的字节数组来构造新的String。
IO流
IO字节输出流
切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象底层传输的始终为二进制数据。
java.io.OutputStream
:此抽象类是表示输出字节流的所有类的超类
定义了一些子类共性的成员方法:
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。
public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b)
:将b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len):
从指定的字节数组写入len字节,从偏移
public abstract void write(int b)
:将指定的字节输出流。
java.io.FileOutPutStream extends OutputStream
FileOutPutStream
:文件字节输出流
作用:把内存中的数据写到硬盘的文件中
构造方法:
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(File file)
创建一个向指定File对象表示的文件中写入数据的文件输出流
参数:写入数据的目的地
String name
:目的地是一个文件的路径
File file
:目的地是一个文件
构造方法的作用:
1、创建一个FileOutputStream对象
2、会根据构造方法中传递的文件/文件路径,创建一个空的文件
3、会把FileOutputStream对象指向创建好的文件
写入数据的原理(内存–>硬盘)
java程序–>JVM(java虚拟机)–>OS(操作系统)–>OS调用写数据的方法–>把数据写入到文件中
字节输出流的使用步骤(重点)
1、创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
2、调用FileOutputStream对象中的方法write,把数据写入到文件中
3、释放资源(流的使用会占用一定的内存,使用完毕要把内存清空,提高程序效率)
public class Demo01OutputStream {
public static void main(String[] args) throws IOException {
//1、创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
FileOutputStream fos = new FileOutputStream("D:\\java\\ceshi\\day01\\a.txt");
//2、调用FileOutputStream对象中的方法write,把数据写入到文件中
//public abstract void write(int b):将指定的字节输出流。
fos.write(97);
//3、释放资源(流的使用会占用一定的内存,使用完毕要把内存清空,提高程序效率)
//public void close():关闭此输出流并释放与此流相关联的任何系统资源。
fos.close();
}
}
文件存储原理
字节输出流写多个字节的方法
一次写多个字节的方法
public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
public class Demo02OutputStream {
public static void main(String[] args) throws Exception {
//1、创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
FileOutputStream fos = new FileOutputStream(new File("D:\\java\\ceshi\\day01\\b.txt"));
//2、调用FileOutputStream对象中的方法write,把数据写入到文件中
//在文件中显示100,写一个字节
fos.write(49);
fos.write(48);
fos.write(48);
//public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
//可一次写多个字节:如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
// 如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
byte[] btes = {65,66,67,68,69};
fos.write(btes);//ABCDE
//public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
//把字节数组的一部分写入到文件中
fos.write(btes,1,2);//BC
//写入字符的方法:可以使用String类中的方法把字符串,转换为字节数组
//byte[] getBytes() 把字符串转换为字节数组
byte[] bytes = "你好".getBytes();//把你好变为字节数组传递到bytes对象中
System.out.println(Arrays.toString(bytes));//[-28, -67, -96, -27, -91, -67]
//utf-8中3个字节是一个字符,GBK中两个字节是一个字符
fos.write(bytes);
//释放资源
fos.close();
}
}
字节输出流的续写和换行
上面追加在b.txt中的内容都是重新写了之后把之前的b.txt覆盖掉了
追加写/续写:使用俩个参数的构造方法
FiLeOutputStream(String name, booLean append )
创建一个向具有指定name的文件中写入数据的输出文件流。
FiLeOutputStream(File fiLe, booLean append)
创建一个向指定 FiLe对象表示的文件中写入数据的文件输出流。
构造方法的参数:
String name, File fiLe:写入数据的目的地
boolean append:追加写开关
true:创建对象不会覆盖原文件,继续在文件的末尾追加写数据
false:创建一个新文件,覆盖原文件
换行:写换行符号
windows:\r\n linux:/n mac:/r
public class Demo03OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\java\\ceshi\\day01\\b.txt",true);
for (int i = 0; i < 10; i++) {
fos.write("你好".getBytes(StandardCharsets.UTF_8));
fos.write("\r\n".getBytes());//"\r\n"也是字符需要转换为字节
}
fos.close();
}
}
IO字节输入流
字节输入流读取字节数据
java.io.InputStream:字节输入流:
此抽象类是表示字节输入流的所有类的超类。
定义了所有子类共性的方法:
int read()
从出入流中读取数据的下一个字节,如果字节已经没有可读的返回-1
int read(byte[] buffer)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
void close()
关闭此输入流并释放与该流有关联的所有系统资源
Java.io.FileInputStream extends InputStream
FileInputStream:文件字节输入流
作用:把硬盘文件中的数据,读取到内存中使用
构造方法:FileInputStream(String name)
FileInputStream(File file)
参数:读取文件的数据源
String name:文件的路径
File file:文件
作用:1、创建一个FileInputStream对象
2、会把FileInputStream对象指定构造方法中要读取的文件
读取数据的原理(硬盘–>内存)
java程序–>JVM–>OS–>OS读取数据的方法–>读取文件
字节输入流的使用步骤(重点)
1、创建FileInputStream对象,构造方法中绑定要读取的数据源
2、使用FileInputStream对象中的方法read,读取文件
3、释放资源
public class Dmeo01InputStream {
public static void main(String[] args) throws Exception {
//1、创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:\\java\\ceshi\\day01\\a.txt");
//2、使用FileInputStream对象中的方法read,读取文件
//int read()读取文件中的一个字节并返回,读取到文件的末尾返回-1
/*int len = fis.read();
System.out.println(len);//97
System.out.println(fis.read());//98
System.out.println(fis.read());//99
System.out.println(fis.read());//-1读取完成返回-1*/
//发现以上读取文件是一个重复过程,所以使用循环忧患
//可是不知文件有多少字节,使用while循环
//布尔表达式(len = fis.read()) != -1
// 1、fis.read()读取一个字节
// 2、len = fis.read()把读取到的字节赋值给变量len
// 3、(len = fis.read()) != -1判断变量len是否不等于-1
int len = 0;//记录读取到的字节
while((len = fis.read()) != -1){
//System.out.println(len);//97 98 99
System.out.print((char) len);//输出不换行,并且输出为字符 abc
}
//3、释放资源
fis.close();
}
}
字节输入流一次读取一个字节/多个字节的原理
字节输入流一次读取多个字节
字节输入流一次读取多个字节的方法
int read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
明确两件事情:
1、方法的参数byte[]的作用
起到缓冲作用,存储每次读取到的多个字节
数组的长度定义为1024的整数倍
2、方法的返回值int是什么
每次读取的有效字节个数
String类的构造方法
String(byte[] bytes):把字节数组转为字符串
String(byte[],int offset,int length)把字节数组的一部分转换为字符串
offset:数组的开始索引 length:转换的字节个数
使用数组就是一个缓冲原理
public class Dmeo02InputStream {
public static void main(String[] args) throws Exception {
//1、创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:\\java\\ceshi\\day01\\b.txt");
//2、使用FileInputStream对象中的方法read读取文件
//int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
byte[] bytes = new byte[2];
int len = fis.read(bytes);
System.out.println(len);//2
//System.out.println(Arrays.toString(bytes));//[65, 66]
System.out.println(new String(bytes));//AB
len = fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//CD
len = fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//
//3、释放资源
fis.close();
}
}
代码优化
public class Dmeo02InputStream {
public static void main(String[] args) throws Exception {
//1、创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("D:\\java\\ceshi\\day01\\b.txt");
//2、使用FileInputStream对象中的方法read读取文件
//int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
/*byte[] bytes = new byte[2];
int len = fis.read(bytes);
System.out.println(len);//2
//System.out.println(Arrays.toString(bytes));//[65, 66]
System.out.println(new String(bytes));//AB
len = fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//CD
len = fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//*/
// 发现以上读取是一个重复的过程,可以使用循环优化
//不知道文件中有多个字节,所以使用while循环
//while循环结束的条件,读取到-1结束
byte[] bytes = new byte[1024];//存储读取到的多个字节
int len = 0;//记录每次读取的有效字节个数
while((len = fis.read(bytes)) != -1){
//System.out.println(new String(bytes));//这里转换不能全部转换,因为这个数组定义为1024个字节
//String(byte[],int offset,int length)把字节数组的一部分转换为字符串
System.out.println(new String(bytes,0,len));
}
//3、释放资源
fis.close();
}
}
文件复制案例
package cn.itcast.day15.demo04;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Demo01CopyFile {
public static void main(String[] args) throws Exception {
long s = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:\\java\\ceshi\\day01\\a.txt");
FileOutputStream fos = new FileOutputStream(new File("D:\\java\\ceshi\\day01\\aaa\\b.txt"));
byte[] bytes = new byte[1024];//存储读取到的多个字节
int len = 0;//记录每次读取的有效字节个数
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
System.out.println(new String(bytes,0,len));
}
fos.close();
fis.close();
long e = System.currentTimeMillis();
System.out.println("复制共耗时:"+ (e-s) +"毫秒");
}
}
使用字节流读取中文的问题
使用字节流读取中文文件,GBK占2个字节,UTF-8占用3个字节,不能读取1/3个字符,所以就需要引入字符流
IO字符输入流
java.io.Reader:字符输入流,是字符输入流的最顶层父类,定义了一些共性的成员方法,是一个抽象类
共性的成员方法:
int read()
读取单个字符并返回
int read(char[] cbuf)
一次读取多个字符,将字符读入数组。
void close()
关闭该流并释放与之关联的所有资源。
java.io.FiLeReader extends InputStreamReader extends Reader
FiLeReader:文件字符输入流
作用:把硬盘文件中的数据以字符的方式读取到内存中
构造方法:
FiLeReader(String fiLeName)
FiLeReader(File file)
参数:读取文件的数据源
String fileName:文件的路径
FiLe file:一个文件
FiLeReader构造方法的作用:
1.创建一个FileReader对象
2.会把FileReader对象指向要读取的文件
字符输入流的使用步骤:
1、创建FileReader对象,构造方法中绑定要读取的数据源
2、使用FileReader对象中的方法read读取文件
3、释放资源
public class Demo01Reader {
public static void main(String[] args) throws Exception {
//1、创建FileReader对象,构造方法中绑定要读取的数据源
FileReader fr = new FileReader("D:\\java\\ceshi\\day01\\b.txt");
/* //2、使用FileReader对象中的方法read读取文件
int len = 0;
while((len = fr.read())!=-1){
System.out.print((char) len);//你好
}*/
//int read(char[] cbuf)一次读取多个字符,将字符读入数组。
char[] cs = new char[1024];//存储读取到的多个字符
int len = 0;//记录的是每次读取的有效字符个数
while ((len = fr.read(cs))!=-1){
//String类的构造方法
//String(char[] value)把字符数组转换为字符串
//String(char[] value,int offset,int count)把字符数组的一部分转换为字符串
//offset数组的开始索引count转换的个数
System.out.println(new String(cs,0,len));
}
//3、释放资源
fr.close();
}
}
IO字符输出流
java.io.writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类
共性的成员方法:
void write(int c)
写入单个字符。
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf,int off, int len)
写入字符数组的某一部分, off数组的开始索引, Len写的字符个数。
void write( String str)
写入字符串。
void write(String str,int off,int len)
写入字符串的某一部分, off字符串的开始索引, Len写的字符个数。
void flush()
刷新该流的缓冲。
void close()
关闭此流,但要先刷新它。
java.io.FileWriter extends OutputStreamWriter extends Writer
FiLewriter:文件字符输出流
作用:把内存中字符数据写入到文件中
构造方法:
FileWriter(File fiLe)
根据给定的File 对象构造一个FiLeWriter 对象。
FiLewriter(String fileName)
根据给定的文件名构造一个FileWriter对象。
参数:写入数据的目的地
String fileName:文件的路径
File file:是一个文件
构造方法的作用:
1.会创建一个FileWriter对象
2.会根据构造方法中传递的文件/文件的路径,创建文件
3.会把FiLeWriter对象指向创建好的文件
字符输出流的使用步骤(重点);
1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
2.使用FiLeWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
public class Demo01Writer {
public static void main(String[] args) throws IOException {
//1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
FileWriter fw = new FileWriter("D:\\java\\ceshi\\day01\\1.txt");
//2.使用FiLeWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
fw.write(98);
//3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
fw.flush();
//4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
fw.close();
}
}
flush方法和close方法的区别
flush
:刷新缓冲区,流对象还可以继续使用
close
:先刷新缓冲区,然后同志系统释放资源,流对象就不能在被使用了
字符输出流写数据的其他方法
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf,int off, int len)
写入字符数组的某一部分, off数组的开始索引, Len写的字符个数。
void write( String str)
写入字符串。
void write(String str,int off,int len)
写入字符串的某一部分, off字符串的开始索引, Len写的字符个数。
public class Demo02Writer {
public static void main(String[] args) throws IOException {
//1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
FileWriter fw = new FileWriter("D:\\java\\ceshi\\day01\\1.txt");
//2、void write(char[] cbuf)写入字符数组
char[] cs = {'a','b','c','d','e','f'};
fw.write(cs);//abcdef
//void write(char[] cbuf,int off, int len)写入字符数组的某一部分, off数组的开始索引, Len写的字符个数
fw.write(cs,1,3);//bcd
//void write( String str)写入字符串
fw.write("小甜甜爱蹦蹦蹦");//小甜甜爱蹦蹦蹦
//void write(String str,int off,int len)写入字符串的某一部分, off字符串的开始索引, Len写的字符个数
fw.write("吸烟有害健康",0,2);//吸烟
fw.close();
}
}
字符输出流的续写和换行
续写和换行
续写和换行:使用两个参数的构造方法
FileWriter(String filename,boolean append)
FileWriter(File file,boolean append)
参数:String fileName,File file:写入数据的目的地
boolean append:续写开关 true:不创建新的文件覆盖源文件,可以续写 false:创建新的文件覆盖源文件
换行:windows:\r\n linux:/n mac:/r
public class Demo03Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\java\\ceshi\\day01\\1.txt",true);
for (int i = 0; i < 10; i++) {
fw.write("HelloWorld" + i + "\r\n");
}
fw.close();
}
}
Properties集合
java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
Properties类表示了一个持久的属性集,Properties可保存在流中或者从流中加载
Properties集合是一个唯一和IO流相结合的集合
可以使用Properties集合中的方法store
,把集合中的临时数据,持久化写入到硬盘中存储
可以使用Properties集合中的方法load
,把硬盘中保存的文件(键值对),读取到集合中使用
Properties集合属性列表中每个键值及其对应值都是一个字符串
Properties集合是一个双列集合,key和value默认都是字符串
使用Properties集合存储数据,遍历
使用Properties集合存储数据,遍历取出Properties集合中的数据
Properties集合属性列表中每个键值及其对应值都是一个字符串
Properties集合有一些操作字符串的特有方法
Object setProperty(String key,String value)
调用Hashtable的方法put
String getProperty(String key)
用指定的键在此属性列表中搜索属性,即通过key找到value
此方法相当于Map集合中的get(key)方法
Set<String> stringPropertyNames
()返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet
private static void show01() {
//创建一个Prperties集合对象
Properties prop = new Properties();
//使用setProperties往集合中添加数据
prop.setProperty("Alice","155");
prop.setProperty("Bob","157");
prop.setProperty("Mallory","185");
//使用stringPropertyNames()把Prperties集合中的键取出,存储到一个Set集合中
Set<String> set = prop.stringPropertyNames();
//遍历Set集合,取出Properties集合的每一个键
for (String key : set) {
//使用getProperty方法通过哦key获取value
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
Properties集合中的方法store
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
void store(OutputStream out,String comments)
void store(Writer writer,String comments)
参数:
OutputStream out:
字节输出流,不能写入中文
Writer writer:
可以写中文
String comments:
注释:用来解释说明保存的文件是做什么用的
不能使用中文,会产生乱码,默认是Unicode编码,一般使用“空字符串”
使用步骤:1、创建Properties集合对象,添加数据
2、创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
3、使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4、释放资源
private static void show02() throws IOException {
//1、创建Properties集合对象,添加数据
Properties prop = new Properties();
//使用setProperties往集合中添加数据
prop.setProperty("Alice","155");
prop.setProperty("Bob","157");
prop.setProperty("Mallory","185");
//2、创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
FileWriter fw = new FileWriter("D:\\java\\ceshi\\day01\\c.txt");
//3、使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
prop.store(fw,"save data");
//4、释放资源
fw.close();
}
//这里因为在字节流中读取文件会因为编码方式的不同,中文会出现乱码,建议使用字符流或者英文
private static void show03() throws IOException {
//1、创建Properties集合对象,添加数据
Properties prop = new Properties();
//使用setProperties往集合中添加数据
prop.setProperty("Alice","155");
prop.setProperty("Bob","157");
prop.setProperty("Mallory","185");
prop.store(new FileOutputStream("D:\\java\\ceshi\\day01\\d.txt"),"save data");
}
Properties集合中的方法load
可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
void load(InputStream inStream)
void load(Reader reader)
参数:InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含有中文的键值对
使用步骤:
1、创建一个Properties集合对象
2、使用Properties集合对象中的方法load读取保存键值对的文件
3、遍历Properties集合
注意:1、存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
2、存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
3、存储键值对的文件中,键与值都是字符串,不用加引号
private static void show04() throws IOException {
//1、创建Properties集合对象,添加数据
Properties prop = new Properties();
//2、使用Properties集合对象中的方法load读取保存键值对的文件
FileInputStream fis = new FileInputStream("D:\\java\\ceshi\\day01\\d.txt");
prop.load(fis);
//3、遍历Properties集合
Set<String> set = prop.stringPropertyNames();
//遍历Set集合,取出Properties集合的每一个键
for (String key : set) {
//使用getProperty方法通过哦key获取value
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
}
缓冲流
缓冲流的原理
BufferedOutputStream字节缓冲输出流
java.io.BufferedOutputStream extends OutputStream
BufferedOutputStream:字节缓冲输出流
继承自父类的共性方法
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。
public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b)
:将b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len)
:从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
public abstract void write(int b)
:将指定的字节输出流。
构造方法:
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流
BufferedOutputStream(OutputStream out,int size)
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
参数:OutputStream out:字节输出流
我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:1、创建FileOutputStream对象,构造方法中绑定要输出的目的地
2、创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
3、使用BufferedOutputStream对象中的方法writer,把数据写入到内部缓冲区中
4、使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
5、释放资源(会先调用flush方法刷新数据,第4步可以省略)
public class Demo02BufferedOutputStream {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("D:\\java\\ceshi\\day01\\e.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("甜是真的甜".getBytes(StandardCharsets.UTF_8));
bos.flush();
bos.close();
}
}
BufferedInputStream字节缓冲输入流
java.io.BufferedInputStream extends InputStream
BufferedInputStream:字节缓冲流
继承自父类的成员方法:
int read()
从出入流中读取数据的下一个字节
int read()
从输入流中读取一数量的字节,并将其存储在缓冲区数组b中
void close()关闭此输入流并释放与该流有关联的所有系统资源
构造方法:BufferedInputStream(InputStream in)
创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用
BufferedInputStream(InputStream in,int size)创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用
参数:InputStream in:字节输入流
我们可以传递FileInputStream,缓冲区会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:1、创建一个FileInputStream对象,构造方法中绑定要读取的数据源
2、创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
3、使用BufferedInputStream对象中的read,读取文件
4、释放资源
5、关闭资源
public class Demo02BufferedInputStream {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("D:\\java\\ceshi\\day01\\a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
/*int len = 0;
while((len = bis.read()) != -1){
System.out.println((char) len);
}*/
byte[] bytes = new byte[1024];
int len = 0;
while((len = bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
bis.close();
}
}
BufferedWriter字符缓冲输出流
java.io.BufferedWriter extends Writer
BufferedWriter:字符缓冲输出流
继承自父类的共性成员方法:
void write(int c)
写入单个字符。
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf,int off, int len)
写入字符数组的某一部分, off数组的开始索引, Len写的字符个数。
void write( String str)
写入字符串。
void write(String str,int off,int len)
写入字符串的某一部分, off字符串的开始索引, Len写的字符个数。
void flush() 刷新该流的缓冲。
void close() 关闭此流,但要先刷新它。
构造方法:
1、BufferedWriter(Writer out)
创建一个使用默认大小缓冲区的缓冲字符输出流
2、BufferedWriter(Writer out,int sz)
创建一个使用给定大小输出缓冲区的新缓冲区字符输出流
参数:Writer out:字符输出流
可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率
int sz:指定缓冲区的大小,不写默认大小
特有成员方法:void newLine()写一个行分隔符。会根据不同的操作系统获取不同的行分隔符
使用步骤:1、创建字符缓冲输出流对象,构造方法中传递字符输出流
2、调用字符缓冲输出流中的方法writer,把数据写入到内存缓冲区中
3、调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
4、释放资源
public class Demo03BufferedWriter {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\java\\ceshi\\day01\\f.txt"));
for (int i = 0; i < 10; i++) {
bw.write("吸烟有害健康!");
bw.newLine();
}
bw.flush();
bw.close();
}
}
BufferedReader字符缓冲输入流
java.io.BufferedReader extends Reader
继承自父类的共性成员方法:
int read()读取单个字符并返回
int read(char[] cbuf)一次读取多个字符,将字符读入数组。
void close()关闭该流并释放与之关联的所有资源。
构造方法:
BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流
BufferedReader(Reader in,int sz)
创建一个使用指定大小输入缓冲区的缓冲字符输入流
参数:Reader in:字符输入流
可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率
特有的成员方法:
String readLine()读取一个文本行,读取一行数据
行的终止符号:通过下列字符之一即可认为某行已将终止:(‘\n’)、回车(‘\r’)或回车后直接跟着换行(\r\n)
返回值:包含该行内容的字符串,不包含任何终止符,如果已经到达流末尾,则返回null
使用步骤:1、创建字符缓冲输入流对象,构造方法中传递字符输入流
2、使用字符缓冲输入流对象中的方法read/readline读取文本
3、释放资源
public class Demo03BufferedReader {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("D:\\java\\ceshi\\day01\\f.txt"));
char[] cs = new char[1024];
int len = 0;
while((len = br.read(cs)) != -1 ){
System.out.println(new String(cs,0,len));
}
br.read();
br.close();
}
}
转换流
字符编码和字符集
编码:字符->字节
解码:字节->字符
OutputStreamWriter
java.io.OutputStreamWriter extends Writer
OutputStreamWriter:字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节
继承父类的共性方法:
void write(int c)
写入单个字符。
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf,int off, int len)
写入字符数组的某一部分, off数组的开始索引, Len写的字符个数。
void write( String str)写入字符串。
void write(String str,int off,int len)写入字符串的某一部分, off字符串的开始索引, Len写的字符个数。
void flush() 刷新该流的缓冲。
void close() 关闭此流,但要先刷新它。
构造方法:
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out,String charsetName)
创建使用指定字符集的OutputStreamWriter
参数:OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
String charsetName
:指定的编码表名称,不区分大小写,可以是UTF-8/utf-8,不指定默认使用utf-8
使用步骤:
1、创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
2、使用OutputStreamWriter对象中的方法writer,把字符转换为字节存储缓冲区中(编码)
3、使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
4、释放资源
public class Demo02OutputStreamWriter {
public static void main(String[] args) throws Exception {
//writer_utf_8();
writer_gbk();
}
//使用转换流OutputStreamWriter写utf-8格式的文件
//
private static void writer_utf_8() throws Exception {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\java\\ceshi\\day01\\a.txt"),"utf-8");
osw.write("你好");
osw.flush();
osw.close();
}
private static void writer_gbk() throws Exception {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\java\\ceshi\\day01\\a.txt"),"gbk");
osw.write("你好a");
osw.flush();
}
}
InputStreamReader
java.io.InputStreamReader extends Reader
InputStreamReader:是字节流通向字符流的桥梁,它使用指定的charset,读取字节并将其解码为字符
继承自父类的共性成员方法:
int read()读取单个字符并返回
int read(char[] cbuf)一次读取多个字符,将字符读入数组。
void close()关闭该流并释放与之关联的所有资源。
构造方法:
1、InputStreamReader(InputStream in)创建一个使用默认字符集的InputStreamReader
2、InputStreamReader(InputStream in,String charsetName)创建使用指定字符集的InputStreamReader
参数:InputStream in:字节输入流用来读取文件中保存的字节
String charsetName:指定的编码表名称,不区分大小写
使用步骤:
1、创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
2、使用InputStreamReader对象中的方法read读取文件
3、释放资源
注意事项:构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
public class Demo03InputStreamReader {
public static void main(String[] args) throws Exception {
writer_utf_8();
}
private static void writer_utf_8() throws Exception {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\java\\ceshi\\day01\\a.txt"),"gbk");
int len = 0;
while((len = isr.read())!=-1){
System.out.println((char) len);
}
isr.close();
}
}
序列化流
序列化和反序列化
ObjectOutputStream:对象的序列化流
java.io.ObjectOutputStream extends OutputStream
ObjectOutputStream:对象的序列化流
作用:把对象以流的方式写入到文件中保存
构造方法:ObjectOutputStream(OutputStream out)创建写入指定OutputStream的ObjectOutputStream
参数:OutputStream out:字节输出流
特有的成员方法:
void writeObject(Object obj)将指定的对象写入ObjectOutputStream
使用步骤:
1、创建一个ObjectOutputStream对象,构造方法中传递字节输出流
2、使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
3、释放资源
序列化和反序列化的时候,会抛出NotSerializableException没有序列化异常
类通过实现java.io.Serializable 接口启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列化
Serializable接口也叫标记型接口
要进行序列化和反序列化的类必须实现Serializable接口,就会给类添加一个标记
当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记
有:就可以序列化和反序列化 没有:就会抛出NotSerializableException异常
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws Exception {
//1、创建一个ObjectOutputStream对象,构造方法中传递字节输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\java\\ceshi\\day01\\Person.txt"));
//2、使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
oos.writeObject(new Person("哈哈哈",18));
// 3、释放资源
oos.close();
}
}
public class Person implements Serializable {
private String name;
private int age;
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
ObjectInputStream:对象的反序列化流
java.io.ObjectInputStream extends InputStream
InputStream:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用
构造方法:ObjectInputStream(InputStream in)
创建从指定InputStream读取的ObjectInputStream
参数:InputStream in:字节输入流
特有的成员方法:Object readObject() 从ObjectInputStream读取对象
使用步骤:
1、创建ObjectInputStream对象,构造方法中传递字节输入流
2、使用ObjectInputStream对象中的方法readObject()读取保存对象的文件
3、释放资源
4、使用读取出来的文件(打印)
readObject()方法声明抛出了ClassNotFoundException异常(class文件找不到异常)
当不存在对象的class文件时抛出此异常
反序列化的前提:
1、类必须实现Serializable
2、必须存在类对应的class文件
public class Demo02ObjectInputStream {
public static void main(String[] args) throws Exception {
// 1、创建ObjectInputStream对象,构造方法中传递字节输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\java\\ceshi\\day01\\Person.txt"));
//2、使用ObjectInputStream对象中的方法readObject()读取保存对象的文件
Object o = ois.readObject();
//3、释放资源
ois.close();
//4、使用读取出来的文件(打印)
System.out.println(o);//Person{name='哈哈哈', age=18}
//强转为Person类型
Person p = (Person) o;
System.out.println(p.getName()+p.getAge());
}
}
transient关键字_瞬态关键字
static关键字:静态关键字
静态优先于非静态加载到内存中(静态优先于对象进入到内存中)
被static修饰的成员变量不能被序列化的,序列化的都是对象
transient关键字:瞬态关键字
被transient修饰成员变量,不能被序列化
如果需要不被序列化,而且非静态就可用transient
InvalidClassException异常
例如:在Person中我们将age的权限改为public ,直接进行反序列化。因为更改了以后其class文件已经被更改,所以就会抛出一个InvalidClassException异常,因为序列号发生了冲突
自动生成serialVersionUID
Preferences -> Inspections -> Serialization issues -> Serialization class without ‘serialVersionUID’ 打上勾
然后在类的名称上Alt+Enter就会自动生成serialVersionUID
import java.io.Serial;
import java.io.Serializable;
public class Person implements Serializable {
@Serial
private static final long serialVersionUID = -7696353887086844926L;
private String name;
private int age;
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
序列化集合案例
import java.io.*;
import java.util.ArrayList;
public class Demo01Test {
public static void main(String[] args) throws Exception {
//定义一个存储Person对象的ArrayList集合
ArrayList<Person> list = new ArrayList<>();
//往ArrayList集合中存储Person
list.add(new Person("小甜甜",18));
list.add(new Person("武哈哈",23));
list.add(new Person("杨蛋蛋",22));
list.add(new Person("赵鱼鱼",22));
//创建一个序列化流ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\java\\ceshi\\day01\\2.txt"));
//使用ObjectOutputStream对象中的方法writeObject,对集合进行序列化
oos.writeObject(list);
//创建一个反序列化ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\java\\ceshi\\day01\\2.txt"));
//使用ObjectInputStream对象中的方法readObject()读取文件中保存的集合
Object o = ois.readObject();
//把Object类型的集合转换为ArrayList类型
ArrayList<Person> list1 = (ArrayList<Person>) o;
//遍历ArrayList
for (Person p : list1) {
System.out.println(p);
}
//释放资源
oos.close();
ois.close();
}
}
打印流
java.io.PrintStream:打印流
PrintStream 为其他输出流添加了功能,使它们能方便打印各种数据值表示形式
PrintStream特点:
1、只负责数据的输出,不负责数据的读取
2、与其他输出流不同,PrintStream永远不会抛出IoException
3、有特有的方法,print,println
void print(任意类型的值)
void println(任意类型的值并换行)
构造方法:
PrintStream(File file)
:输出的目的地是一个文件
PrintStream(OutputStream out)
:输出的目的地是一个字符输出流
PrintStream(String fileName)
:输出的目的地是一个文件路径
PrintStream extends OutputStream
继承自父类的共性方法
public void close():关闭此输出流并释放与此流相关联的任何系统资源。
public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
public abstract void write(int b):将指定的字节输出流。
注意事项:如果使用继承自父类的writer方法写数据,那么查看数据的时候会查询编码表97->a
如果使用自己特有的方法print,println方法写数据,写的数据原样输出97->97
public class Demo01PrintStream {
public static void main(String[] args) throws Exception {
//创建打印流PrintStream对象,构造方法中绑定要输出的目的地
PrintStream ps = new PrintStream("D:\\java\\ceshi\\day01\\3.txt");
//如果使用继承自父类的writer方法写数据,那么查看数据的时候会查询编码表97->a
ps.write(97);//a
//如果使用自己特有的方法print,println方法写数据,写的数据原样输出97->97
ps.println(97);//97 可输出任意的字符类型
ps.close();
}
}
打印输出语句的目的地
可以改变输出语句的目的地(打印流的流向)
输出语句,默认在控制台输出
使用System类中setOut方法改变输出语句的目的地为参数传递的打印流的目的地
static void setOut(PrintStream out)重新分配标准输出流
public class Demo02PrintStream {
public static void main(String[] args) throws Exception {
System.out.println("这是在控制台输出的!");
PrintStream ps = new PrintStream("D:\\java\\ceshi\\day01\\4.txt");
System.setOut(ps);//方法改变输出语句的目的地为参数传递的打印流的目的地
System.out.println("这是在打印流的目的地中输出!");
ps.close();
}
}