文件操作和IO
1. 关于文件的一些基本概念
2. Java中的操作文件
构造方法:
方法:
public class FileDemo1 {
public static void main(String[] args) throws IOException {
File file = new File("./test1.txt");
System.out.println(file.getParent());
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());//绝对路径
System.out.println(file.getCanonicalPath());//修饰过的绝对路径,去掉了一些 ././
}
}
3. 文件内容的读写 —— 数据流
3.1 从文件中读数据(InputStream)
1. 逐个字节读(无汉字)
public class FileDemo9 {
public static void main(String[] args) throws IOException {
InputStream inputStream=null;
try{
//1.这个创建实例的过程就相当于打开文件
inputStream = new FileInputStream("./test1.txt");
//2.逐个字节的读取出文件内容
while(true){
int b=inputStream.read();
if(b==-1){
break;
}
System.out.printf("%c", b);//注意:这里用的是printf
}
}catch (IOException e){
e.printStackTrace();
}finally {
//3.关闭文件,如果不关闭就容易造成资源泄露
inputStream.close();
}
}
}
2. 一次读取多个字节(无汉字)
public class FileDemo11 {
public static void main(String[] args) {
//一次读取 1024 个字节
try(InputStream inputStream = new FileInputStream("./test1.txt")){
byte[] buffer = new byte[1024];
while(true){
int len=inputStream.read(buffer);//返回的是读取到的字节数
//读到文件结尾的时候,就会返回-1
if(len==-1){
break;
}
for(int i=0;i<len;i++){
System.out.printf("%c",buffer[i]);
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
3.当读取文件中有汉字时
public class FileDemo12 {
public static void main(String[] args) {
try(InputStream inputStream = new FileInputStream("./test1.txt")){
try(Scanner scanner =new Scanner(inputStream,"UTF-8");){
while (scanner.hasNext()){
String s =scanner.next();
System.out.print(s);//注意:这里是print
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
3.2 往文件中写入数据(OutputStream)
1. 几种常规写入方式
public class FileDemo13 {
public static void main(String[] args) {
//一旦按照OutputStream的形式打开文件,就会把文件原来的内容给清空
try(OutputStream outputStream = new FileOutputStream("./test1.txt")){
//写入一个字符
outputStream.write('a');
//按照字节来写入
byte[] buffer = new byte[]{(byte)'a',(byte)'b',(byte)'c',(byte)'d',(byte)'e'};
outputStream.write(buffer);
//按照字符串写入
String s = "hello world";
outputStream.write(s.getBytes());//s.getBytes(),将s转为一个字节数组
//刷新
outputStream.flush();
}catch (IOException e){
e.printStackTrace();
}
}
}
2. 用 PrintWriter 进行写入
public class FileDemo14 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("./test1.txt")){
try(PrintWriter writer = new PrintWriter(outputStream)){//于Scanner的定位类似
writer.println("hello world");
}
}catch (IOException e){
e.printStackTrace();
}
}
}
3. 关于 flush() 刷新缓冲区
缓冲区的设置是为了提高计算机读写时的效率。
在把内存上的东西写入到磁盘时,计算机读写内存的速度时比较快的,但是读写磁盘的速度是比较慢的,这个速度不匹配的问题是会影响工作效率的,所以就引入了缓冲区,减少直接对磁盘的访问次数,那是如何减少的呢?
计算机从内存中放到的数据先放到缓冲区,等到缓冲区满了之后,再把缓冲区中的内容送到磁盘
3.3 什么样的类能放到try()里面呢?
以上面放入到try()当中的InputStream 和 OutputStream 做展示
3.4 未及时close导致的资源泄漏问题
4. 文件操作案例
案例1
案例描述:扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件
代码实现:
public class FileDemo15 {
public static void main(String[] args) throws IOException {
//1.让用户输入一个目录 和 要查询的关键字
System.out.println("请输入要扫描的目录:");
Scanner scanner = new Scanner(System.in);
String root =scanner.next();
File rootDir= new File(root);
if(!rootDir.isDirectory()){
System.out.println("您输入的路径错误,程序退出!");
return;
}
System.out.println("请输入要查找的文件名中包含的关键词:");
String token = scanner.next();
//2.递归遍历查找
List<File> result = new ArrayList<>();//表示递归遍历的结果,包含所有带有token该关键字的文件名
scanDir(rootDir,token,result);
//3.遍历result,用用户是否要删除文件,根据用户的输入决定是否删除
for(File f:result){
System.out.println(f.getCanonicalPath()+"是否要删除?(Y/N)");
String input = scanner.next();
if(input.equals("Y")){
f.delete();
System.out.println("删除成功!");
}
}
}
private static void scanDir(File rootDir,String token,List<File> result) throws IOException {
// list 返回的是一个String类型的文件名,使用listFiles直接得到的就是File对象
File[] files = rootDir.listFiles();
if(files==null||files.length==0){//当前目录是一个空的目录
return;
}
for(File f:files){
if(f.isDirectory()){
//如果当前文件是一个目录,就继续递归
scanDir(f,token,result);
}
else{
//当前文件是一个普通文件,就判断一下这个文件是否包含了待查找的关键字
if(f.getName().contains(token)){
result.add(f.getCanonicalFile());
}
}
}
}
}
案例2
进行普通文件的复制
public class FileDemo16 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要复制的文件路径(绝对路径):");
String sourcePath=scanner.next();
File sourceFile = new File(sourcePath);
if(!sourceFile.isFile()){
System.out.println("文件路径错误,程序直接退出");
return;
}
System.out.println("请输入目标目录路径(绝对路径):");
String targetPath=scanner.next();
File targeFile=new File(targetPath);
if(targeFile.exists()){
System.out.println("目标文件已经存在,程序直接退出");
return;
}
if(!targeFile.getParentFile().exists()){
//目标文件的父目录不存在,就退出
System.out.println("目标文件的父目录不存在,程序直接退出");
}
try(InputStream inputStream = new FileInputStream(sourceFile);
OutputStream outputStream = new FileOutputStream(targeFile)){
//从inputStream中读取,写入到outputStream
while(true){
byte[] buffer = new byte[1024];
int len = inputStream.read(buffer);
if(len==-1){
break;
}
outputStream.write(buffer,0,len);
}
outputStream.flush();
}catch(IOException e){
e.printStackTrace();
}
System.out.println("复制成功");
}
}
案例3
扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
public class FileDemo17 {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
//1.用户输入一个路径,待搜索的路径
System.out.println("请输入要查找的目录:");
String rootDir = scanner.next();
File rootFile = new File(rootDir);
if(!rootFile.isDirectory()){
System.out.println("该目录不存在,或者不是文件,程序直接退出!!");
return;
}
//2.再让用户输入一个查询词,表示要查找的内容
System.out.println("请输入你要查找的词:");
String query = scanner.next();
//3.遍历目录以及文件,进行匹配
List<File> result = new ArrayList<>();
scanDirWithContent(rootFile,query,result);
//4.把路径打印出来
for(File f :result){
System.out.println(f.getCanonicalPath());
}
}
private static void scanDirWithContent(File rootFile,String query,List<File> result){
File[] files = rootFile.listFiles();
if(files==null||files.length==0){
//针对空的目录直接返回
return;
}
for(File f:files){
if(f.isDirectory()){
scanDirWithContent(f,query,result);
}else{
if(f.getName().contains(query)){//看看文件名称是否包含
result.add(f);
}else if(isContentContains(f,query)){//看看文件内容是否包含
result.add(f);
}
}
}
}
private static boolean isContentContains(File f,String query){
StringBuilder stringBuilder = new StringBuilder();
//打开 f 这个文件,依次取出每一行结果,去和 query 进行一个 indexof
try(InputStream inputStream = new FileInputStream(f)){
Scanner scanner= new Scanner(inputStream,"UTF-8");
while(scanner.hasNextLine()){
String line=scanner.nextLine();
stringBuilder.append(line+'\n');
}
}catch (IOException e){
e.printStackTrace();
}
return stringBuilder.indexOf(query)!=-1;
}
}