File和IO流
File
File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)。
IO流
用于读写数据的(可以读写文件,或网络中的数据...)
File代表文件 IO流用来读写数据
File
创建对象
创建File类的对象
注意:
File对象既可以代表文件、也可以代表文件夹。
Fil封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。
绝对路径和相对路径
绝对路径从盘符开始:
相对路径不带盘符,默认直接到当前工程下的目录寻找文件:
java
package com.itchinajie.d1_file;
import java.io.File;
/*
*目标掌握File创建对象,代表具体文件的方案
* */
public class FileTest1 {
public static void main(String[] args) {
//1、创建一个File对象,指代某个具体文件
//路径分隔符
//File file1 = new File("\u202AE:/Java/resource/ab.txt");
//File file1 = new File("\u202AE:\\Java\\resource\\ab.txt");
File file1 = new File("E:" + File.separator + "Java" + File.separator + "resource" + File.separator + "ab.txt");
System.out.println(file1.length());//文件大小(字节)
File file2 = new File("E:/Java");
System.out.println(file2.length());
//注意:File对象可以指代一个不存在的文件路径
File f3 = new File( "D:/resource/aaaa.txt");
System.out.println(f3.length());
System.out.println(f3.exists()); // false
//如果要定位的文件在模块中,直接右键可以复制文件路径
//绝对路径
//File file4 = new File("E:\\Java\\code\\file-io-app\\src\\itchinajie.txt");
//相对路径(重点):不带盘符,默认是直接去工程下找文件
File file4 = new File("file-io-app\\src\\itchinajie.txt");
System.out.println(file4.length());
}
}
判断文件类型和获取文件信息功能
源码展示:
java
//1.创建文件对象,指代某个文件
File f1 = new File( "E:\\Java\\code\\file-io-app\\src\\itchinajie.txt");
//File f1 = new File("D:/resource/");
//2、public boolean exists():判断当前文件对象,对应的文件路径是否存在,存在返回true.
System.out.println(f1.exists());
//3、public boolean isFile():判断当前文件对象指代的是否是文件,是文件返回true,反之。
System.out.println(f1.isFile());
//4、public boolean isDirectory():判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。
System.out.println(f1.isDirectory());
//5.public String getName():获取文件的名称(包含后缀)
System.out.println(f1.getName());
//6.public long length():获取文件的大小,返回字节个数
System.out.println(f1.length());
//7.publicLongLastModified():获取文件的最后修改时间。
long time = f1.lastModified();
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss");
System.out.println(sdf.format(time));
//8.public String getPath():获取创建文件对象时,使用的路径
File f2 = new File( "E:\\Java\\code\\file-io-app\\src\\itchinajie.txt");
File f3 = new File( "src/itchinajie.txt");
System.out.println(f2.getPath());
System.out.println(f3.getPath());
//9.public String getAbsolutePath():获取绝对路径
System.out.println(f2.getPath());
System.out.println(f3.getPath());
创建和删除文件
File类创建文件功能
File类删除文件的功能
注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。
源码展示:
java
package com.itchinajie.d1_file;
import java.io.File;
import java.io.IOException;
/*
* 目标:掌握File提供的创建和删除文件相关的方法
* */
public class FileTest3 {
public static void main(String[] args) throws IOException {
//1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
File f1 = new File( "E:\\Java\\code\\file-io-app\\src\\abcd.txt");
System.out.println(f1.createNewFile());
//2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
File f2 = new File( "E:\\Java\\code\\file-io-app\\src\\ddd");
System.out.println(f2.mkdir());
//3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
File f3 = new File( "E:\\Java\\code\\file-io-app\\src\\aaa\\bbb\\ccc");
System.out.println(f3.mkdirs());
//3、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
System.out.println(f1.delete());
System.out.println(f2.delete());
File f4 = new File( "E:\\Java");
System.out.println(f4.delete());
}
}
遍历文件夹
File类提供的遍历文件夹的功能
使用listFiles方法时的注意事项:
当主调是文件,或者路径不存在时,返回null;
当主调是空文件夹时,返回一个长度为0的数组;
当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回;
当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件;
当主调是一个文件夹,但是没有权限访问该文件夹时,返回null。
源码展示:
java
package com.itchinajie.d1_file;
import java.io.File;
import java.util.Arrays;
/*
* 目标:掌握File提供的遍历文件夹方法
* */
public class FileTest4 {
public static void main(String[] args) {
//1、publicString[] list():获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
File f1 = new File("E:\\Java\\code");
String[] names = f1.list();
for (String name : names) {
System.out.println(name);
}
//2、public File[]listFiles():(重点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
File[] files = f1.listFiles();
for (File file : files) {
System.out.println(file.getAbsolutePath());
}
File f = new File("D:/resource/aaa");
File[] files1 = f.listFiles();
System.out.println(Arrays.toString(files1));
//使用listFile方法时的注意事项:
//当主调是文件,或者路径不存在时,返回null
//当主调是空文件夹时,返回一个长度为0的数组
//当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
//当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
//当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
}
}
方法递归
认识递归的形式
什么是方法递归?
递归是一种算法,在程序设计语言中广泛应用。
从形式上说:方法调用自身的形式称为方法递归(recursion)。
递归的形式
直接递归:方法自己调用自己。
间接递归:方法调用其他方法,其他方法又回调方法自己。
使用方法递归时需要注意的问题:
递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。
java
package com.itchinajie.d2_recursion;
/*
* 目标:认识一下递归的形式
* */
public class RecursionTest1 {
public static void main(String[] args) {
test1();
}
//直接方法递归
public static void test1(){
System.out.println("---test1---");
test1();
}
//间接方法递归
public static void test2(){
System.out.println("---Test2---");
test3();
}
public static void test3(){
System.out.println("---Test3---");
test2();//间接递归
}
}
递归的应用、执行流程、算法思想
java
package com.itchinajie.d2_recursion;
/*
*目标:掌握递归的应用,执行流程和算法思想
* */
public class RecursionTest2 {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n){
//终结点
if (n == 1){
return 1;
}else {
return f(n-1) * n;
}
}
}
package com.itchinajie.d2_recursion;
/*
*掌握递归的应用2
* */
public class RecursionTest2_1 {
public static void main(String[] args) {
//计算1 - n 的和的结果,用递归的思想解决
System.out.println(f(10));
}
public static int f(int n){
if (n == 1){
return 1;
}else {
return n + f(n -1);
}
}
}
递归算法的三大要素
递归的公式:f(n)=f(n-1)*n;
递归的终结点:f(1)
递归的方向必须走向终结点:
java
package com.itchinajie.d2_recursion;
/*
*掌握递归的应用3
* */
public class RecursionTest2_2 {
public static void main(String[] args) {
//猴子吃桃
//猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了个
//第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又多吃了一个
//以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个
//等到第10天的时候发现桃子只有1个了。
// 需求:请问猴子第一天摘了多少个桃子?
//公式:f(x) - f(x) / 2 - 1 = f(x + 1)
//变形:f(x) = 2f(x + 1) + 2
System.out.println(f(1));
System.out.println(f(2));
System.out.println(f(3));
}
public static int f(int n){
if (n == 10){
return 1;
}else {
return 2*f(n + 1) +2;
}
}
}
其他应用:文件搜索
java
package com.itchinajie.d2_recursion;
import java.io.File;
import java.io.IOException;
/*
* 目标:掌握文件搜索的实现
* */
public class RecursionTest3 {
public static void main(String[] args) throws IOException {
searchFile(new File("E:/"),"QQ.exe");
}
/**
* 去目录下搜索某个文件
* @param dir
* @param fileName
*/
public static void searchFile(File dir,String fileName) throws IOException {
//1、把非法的情况拦截住
if (dir == null || !dir.exists() || dir.isFile()){
return;
}
//2、dir不是null,存在,一定目录对象
//获取当前目录下的以及文件对象
File[] files = dir.listFiles();
//3、判断当前目录下是否存在一级对象,以及是否可以拿到一级文件对象
if (files != null && files.length > 0){
//4、遍历全部一级文件对象
for (File f : files) {
//5、判断文件是否是文件还是文件夹
if (f.isFile()){
//判断这个文件名是否是我们要找的
if (f.getName().contains(fileName)){
System.out.println("找到了:" + f.getAbsolutePath());
Runtime runtime = Runtime.getRuntime();
runtime.exec(f.getAbsolutePath());
}
}else {
//是文件夹,继续重复这个过程(递归)
searchFile(f,fileName);
}
}
}
}
}
字符集
常见字符集
ASCLL、Unicode、UTF-8
其中UTF-8 是Unicod字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节 ;英文字符、数字等只占1个字节(兼容标准ASCLL编码),汉字字符占用3个字节。
注意:技术人员在开发时都应该使用UTF-8编码!
注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。
注意2:英文,数字一般不会乱码,因为很多字符集都兼容了ASCLL编码。
字符集的编码、解码操作
编码:把字符按照指定字符集编码成字节。
解码:把字节按照指定字符集解码成字符。
java
package com.itchinajie.d4_charset;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/*
*目标:掌握如何使用Java代码完成对字符的编码和解码
* */
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
//1、编码
String data = "a我b";
byte[] bytes = data.getBytes();//默认是按照平台字符集(UTF-8)进行编码的
System.out.println(Arrays.toString(bytes));
//按照指定字符集进行编码
byte[] gbks = data.getBytes("GBK");
System.out.println(Arrays.toString(gbks));
//2、解码
String string = new String(bytes);//按照平台默认编码(UTF-8)解码的
System.out.println(string);
String string1 = new String(gbks,"GBK");
System.out.println(string1);
}
}
IO流
IO流简单描述
IO流的分类
流的四大类:
字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流 。
字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。
字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流。
字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。
IO流的体系
IO流-字节流
FilelnputStream(文件字节输入流)
每次读取一个字节
作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。
java
package com.itchinajie.d5_byte_stream;
import java.io.*;
/*
* 目标掌握文件字节输入流,每次读取一个字节
* */
public class FileInputStreamTest1 {
public static void main(String[] args) throws IOException {
//1、创建文件字节输入流管道,与源文件接通
//InputStream is = new FileInputStream(new File("src/itchinajie01.txt"));
//简化写法,推荐使用
InputStream is = new FileInputStream(("file-io-app/src/itchinajie01.txt"));
//2、开始读取文件的字节数据
//public int read();每次读取一个字节返回,如果没有数据了,返回-1
// int read = is.read();
// System.out.println((char)read);
//
// int read1 = is.read();
// System.out.println((char ) read1);
//
// int read2 = is.read();
// System.out.println( read2);
//3、使用循环改造上面的代码
int b;//用于记住读取的字节
while ((b = is.read()) != -1){
System.out.print((char)b);
}
//读取数据的性能很差
//读取汉字会输出乱码,无法避免
//流使用完之后,必须关闭,释放系统资源
is.close();
}
}
注意:使用FilelnputStream每次读取一个字节,读取性能较差,并且读取汉字输出会乱码。
每次读取多个字节
作用:以内存为基准,把文件中的数据以字节的形式读入到内存中去。
java
package com.itchinajie.d5_byte_stream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/*
* 目标:掌握使用FileInputStream每次读取多个字节
* */
public class FileInputStreamTest2 {
public static void main(String[] args) throws IOException {
//1、创建一个字节输入流对象代表字节输入流管道与源文件接通
FileInputStream is = new FileInputStream("file-io-app\\src\\itchinajie02.txt");
//2、开始读取文件中的字节数据,每次读取多个字节
// public int read(byte b [ ])throws IOException
// 每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1.
/* byte[] buffer = new byte[3];
int len = is.read(buffer);
String rs = new String(buffer);
System.out.println(rs);
System.out.println("当次读取的字节数量:" + len);
int len2 = is.read(buffer);
//注意:读取多少,就倒多少
String rs2 = new String(buffer,0,len2);
System.out.println(rs2);
System.out.println("第二次读取的字节数:" + len2);
int len3 = is.read(buffer);
String rs3 = new String(buffer);
System.out.println(rs3);
System.out.println("第二次读取的字节数:" + len3);*/
//3、使用循环改造
byte[] buffer = new byte[3];
int len;//记住每次读了多少个字节
while((len = is.read(buffer)) != -1){
//注意:读取多少,就倒多少
String rs = new String(buffer, 0, len);
System.out.print(rs);
}
//性能得到了明显的提升!!
//这种方案也不能避免读取文字出现乱码的问题!!
is.close();
}
}
一次性读取完全部字节
方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节。
方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回。
java
package com.itchinajie.d5_byte_stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/*
* 目标:使用文件字节输入流一次读完全部字节
* */
public class FileInputStreamTest3 {
public static void main(String[] args) throws IOException {
//1、一次性读取完文件的全部字节到一个字节数组中去。
//创建一个字节输入流管道与源文件接通
FileInputStream is = new FileInputStream("file-io-app\\src\\itchinajie03.txt");
//方法一:
//2、准备一个字节数组,大小与文件的大小正好一样大
/* File f = new File("file-io-app\\src\\itchinajie03.txt");
long size = f.length();
byte[] buffer = new byte[(int)size];
int len = is.read(buffer);
System.out.println(new String(buffer));
System.out.println(size);
System.out.println(len);*/
//方法二:
byte[] buffer = is.readAllBytes();
System.out.println(new String(buffer));
}
}
注意:直接把文件数据全部读取到一个字节数组可以避免乱码,但如果文件过大,创建的字节数组也会过大,可能引起内存溢出,所以读写文本内容更适合用字符流,而字节流适合故数据的转移,如:文件复制等。
FileOutputStream(文件字节输出流)
作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去。
java
package com.itchinajie.d5_byte_stream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/*
* 目标:掌握文件字节输出流FileOutputStream的使用
* */
public class FileOutputStreamTest4 {
public static void main(String[] args) throws IOException {
//1、创建一个字节输出流管道与目标文件接通
//覆盖管道:覆盖之前的数据
// OutputStream os =
// new FileOutputStream("file-io-app\\src\\itchinajie04out.txt");
//追加数据的管道
OutputStream os =
new FileOutputStream("file-io-app\\src\\itchinajie04out.txt",true);
//2、开始写字节数据出去了
os.write(97);//97就是一个字节,代表a
os.write('b');//'b'也是一个字节
//os.write('杰');//[ooo]默认只能写出去一个字节
byte[] bytes = "我爱你中国abc".getBytes();
os.write(bytes);
os.write(bytes,0,15);
//换行操作
os.write("\r\n".getBytes());
os.close();//关闭流
}
}
案例:文件复制
字节流非常适合做一切文件的复制操作
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!
java
package com.itchinajie.d5_byte_stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
/*
* 目标:使用字节流完成对文件的复制操作
* */
public class CopyTest5 {
public static void main(String[] args) throws Exception {
//需求:复制照片
//1、创建一个字节输入流管道与源文件接通
InputStream is = new FileInputStream("E:\\Java\\tupian\\meinv.jpg");
//2、创建一个字节输出流管道与目标文件接通
FileOutputStream os = new FileOutputStream("C:\\data\\meinv1.jpg");
//3、创建一个字节数组,负责转移字节数据
byte[] buffer = new byte[1024];//1kB
//4、从字节输入流中读取字节数据,写出到字节输出流中。读多少写出去多少。
int len;//用来记住每次读取了多少个字节
while((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}
os.close();
is.close();//后创建的六先关掉,先创建的流后关掉
System.out.println("复制完成~~");
}
}
释放资源的方式
try-catch-finally
finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非VM终止。
作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)。
java
package com.itchinajie.resource;
/*
* 目标:认识try-catch-finally
* */
public class Test1 {
public static void main(String[] args) {
try {
System.out.println(10 / 0);
//return;//跳出方法执行
//System.exit(0);//虚拟机
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("====~~牛逼~~====");
}
System.out.println(chu(10, 2));
}
public static int chu(int a,int b) {
try {
return a / b;
} catch (Exception e) {
e.printStackTrace();
return -1;//代表的是出现异常
} finally {
//千万不要在fina11y中返回数据!
return 111;
}
}
}
try-with-resource
JDK7开始提供了更简单的资源释放方案:try-with-resource。
java
package com.itchinajie.resource;
public class Myconnection implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("释放了与某个硬件的链接资源");
}
}
package com.itchinajie.resource;
import java.io.*;
/*
* 目标:掌握释放资源的方式
* */
public class Test2 {
public static void main(String[] args){
InputStream is = null;
OutputStream os = null;
try {
//1、创建一个字节输入流管道与源文件接通
is = new FileInputStream("E:\\Java\\tupian\\meinv.jpg");
//2、创建一个字节输出流管道与目标文件接通
os = new FileOutputStream("C:\\data\\meinv1.jpg");
//3、创建一个字节数组,负责转移字节数据
byte[] buffer = new byte[1024];//1kB
//4、从字节输入流中读取字节数据,写出到字节输出流中。读多少写出去多少。
int len;//用来记住每次读取了多少个字节
while((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}
System.out.println("复制完成~~");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//释放资源操作
try {
if (os!= null)os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if (is != null)is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
java
package com.itchinajie.resource;
import java.io.*;
/*
* 目标:掌握释放资源的方式2
* */
public class Test3 {
public static void main(String[] args) throws Exception {
try(//1、创建一个字节输入流管道与源文件接通
InputStream is = new FileInputStream("E:\\Java\\tupian\\meinv.jpg");
//2、创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("C:\\data\\meinv1.jpg");
//注意:这里只能放置资源对象。(流对象)
//int age=21;
//什么是资源呢?资源都是会实现AutoCloseable.接口。资源都会有一个close方法,并且资源放到这里后
//用完之后,会被自动调用其cL0se方法完成资源的有放操作。
Myconnection conn = new Myconnection();
){
//3、创建一个字节数组,负责转移字节数据
byte[] buffer = new byte[1024];//1kB
//4、从字节输入流中读取字节数据,写出到字节输出流中。读多少写出去多少。
int len;//用来记住每次读取了多少个字节
while((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}
System.out.println(conn);
System.out.println("复制完成~~");
} catch (IOException e) {
e.printStackTrace();
}
}
}
(本章图片均来自于黑马程序员视频)