有关文件的方法汇总:
文章目录
指定目录下显示一级子目录信息
中心说明:该任务重在显示格式的设置上
主要涉及:File类中listFiles()方法,其返回值类型为File对象数组;isFile()或者isDirectory()方法;lastModified()获取文件最后修改时间;getName()获取文件名;NumberFormat的子类DecimalFormat(“自定义显示格式”)用于对文件大小显示进行格式化处理;String类中substring(起始索引,结束索引(不含))方法对文件名显示长度的处理可以使得各文件有对齐效果。
/**
* 根据提供的目录,显示目录下子文件或子目录的信息
* FileItem为包含自定义文件各属性的类
* @param dir
*/
public ArrayList<FileItem> showList(File dir) {
//以下集合不适合设为全局变量
ArrayList<FileItem> list = new ArrayList<FileItem>();
// 获取目录下所有的File对象
File[] files = dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
//获取目录中的一个File对象
File f = files[i];
//将File转换为FileItem
FileItem fi = converter(f, i);
list.add(fi);
}
}
return list;
}
private FileItem converter(File f, int num) {
FileItem item = new FileItem();
item.setNum(num + 1);
item.setName(f.getName());
item.setType(f.isFile() ? "文件" : "目录");
item.setLastModipy(new Date(f.lastModified()));
//获取文件的大小
if(f.isFile()) {
//获取标准文件的大小
long size = f.length();
String fileSize = formatSize(size);
item.setSize(fileSize);
}
return item;
}
/**
* 以固定格式显示文件字节大小
* @param size
* @return
*/
private String formatSize(long size) {
if(size<1024) {
return size+"字节";
}else {
NumberFormat fmt = new DecimalFormat("#,###KB");
return fmt.format(size/1024);
}
}
FileItem类中:
@Override
public String toString() {
DateFormat fmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss SSS");
String time = fmt.format(lastModipy);
if(name.length()>2) {
name = name.substring(0,1)+"···";
}
return num +"\t"+name+"\t"+type+"\t"+time+"\t"+size;
}
多级目录展示
中心说明:该任务要对指定目录下进行彻底的遍历,并按子目录等级显示各目录名称,主要难点为递归的设计和级数标记的设置。
涉及:循环嵌套使用
public void readDir(File f,int n) {
//n初始传递值为0,每递归1次表示目录级数增加1层(不可放到for循环内部)
n++;
if(f.isDirectory()) {
for (int i = 0; i < f.listFiles().length; i++) {
for (int j = 0; j < n; j++) {
System.out.print("--");
}
System.out.println(f.listFiles()[i].getName());
if(f.listFiles()[i].isDirectory()) {
readDir(f.listFiles()[i],n);
}
}
}
}
文件或(多级)目录的删除
中心说明:在文件递归的同时考虑File类delete()方法的使用,该方法只能对标准文件和空文件夹进行删除。
涉及:递归循环,delete()方法
import java.io.File;
/**
* 删除文件/目录
* @author dell
*
*/
public class DelDir {
public void delTex(File f) {
File[] filess = f.listFiles();
if(filess != null) {
for (int i = 0; i < filess.length; i++) {
File fi = filess[i];
if(fi.isFile()) {
System.out.println("删除文件"+"\t"+fi.getName());
fi.delete();
}else {
delTex(fi);
}
}
}
System.out.println("删除目录"+"\t"+f.getName());
f.delete();
}
拷贝单个标准文件
中心说明:主要利用InputStream和OutputStream流,下例中由于finally语句块里需对IO流进行关闭操作,因此本在try语句块中对IO流进行的声明放到了try语句块的外层了。
/**
* 拷贝单个标准文件
* @param sourceFile 源文件
* @param targetDir 目标拷贝至文件
*/
public static void copyFile(File sourceFile, File targetDir) {
//判断目标文件是否存在,若不存在创建
if(!targetDir.exists()) {
targetDir.mkdirs();
}
//根据提供的源文件文件名,结合目标目录构建一个目标文件对象
File target = new File(targetDir,sourceFile.getName());
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(sourceFile);
os = new FileOutputStream(target);
byte[] b = new byte[1024];
int len = 0;
System.out.println("开始拷贝...");
while((len = is.read(b)) != -1) {
//将读取的字节数组从0开始写入len个字节到目标文件
os.write(b, 0, len);
}
System.out.println("拷贝完成");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//Closeable接口(jdk1.5)
if(Objects.nonNull(os)) {
os.close();
}
if(Objects.nonNull(is)) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
RandomAccessFile实现文件拷贝
中心说明:该方法功能与上一个方法拷贝功能完全一样,只是为了应用到RandomAccessFile流即可读入又可输出(“r”和“rw”)的特点,对于实在不想找输入流输出流的时候可以用用,至少复制粘贴是可以安排的。不同的是这里目标文件放的是完整类路径,上一个方法放的是目录路径,这里也无需担心该文件不存在会不会出问题,因为存在的话会覆盖原文件内容,不存在的话,在拷贝过程中,程序会自行进行创建。
/**
* 使用RandomAccessFile实现文件拷贝
* @param args
* @throws IOException
*/
public void copy() throws IOException {
//源文件
File source = new File("");
//目标文件
File target = new File("");
RandomAccessFile rafSource = new RandomAccessFile("源文件完整路径","r");
RandomAccessFile rafTarget = new RandomAccessFile("目标文件路径","rw");
//拷贝过程
System.out.println("开始拷贝");
byte[] b = new byte[1024];
int pos = 0;
while((pos = rafSource.read(b)) != -1) {
String s = new String(b,0,pos);
rafTarget.writeChars(s);
System.out.println(s);
}
rafSource.close();
rafTarget.close();
System.out.println("拷贝完成!");
}
拷贝目录
/**
* 拷贝目录(目录下包含多级子目录和文件)
*
* @param source
* @param targetDir 目标目录
*/
public static void copy(File source, File targetDir) {
//判断源文件是否是标准文件
if (source.isFile()) {
//如果源文件是标准文件,则直接进行文件拷贝
copyFile(source, targetDir);
}else {
//在目标目录下创建一个跟源目录同名的子目录(未创建)
targetDir = new File(targetDir,source.getName());
//如果目标目录不存在则创建
if(!targetDir.exists())targetDir.mkdirs();
File[] subFiles = source.listFiles();
//获取源目录下所有的子文件
if(subFiles != null) {
//遍历所有的子文件
for(int i = 0;i<source.length();i++) {
copy(subFiles[i],targetDir);
}
}
}
}
文件监听(是否有发生修改,若修改则返回文件被修改的时间)
中心说明:与下一个方法(线程)可同时进行,线程之间完成情况上互不影响,由于是监听机制,都用了while(true)死循环实现,通过sleep(毫秒数)的使用设置监听结果反馈间隔时间。
import java.io.File;
public class FileListener extends Thread{
private File target;
private long lastModify;
public FileListener(File target) {
this.target = target;
}
public void run() {
lastModify = target.lastModified();
System.out.println("开始监控:"+Tools.getFmtTime(lastModify));
while(true) {
long newTime = target.lastModified();
if(newTime != lastModify) {
System.out.println("文件被修改,修改时间:"+Tools.getFmtTime(newTime));
lastModify = newTime;
}
try {
sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
对一级子目录下全是标准文件的目录进行监听
import java.io.File;
import java.time.LocalDateTime;
public class DirListener extends Thread{
private File dir;
private File[] files;
public DirListener(File dir) {
this.dir = dir;
}
public void run() {
files = dir.listFiles();
System.out.println("开始监控目录"+LocalDateTime.now());
while(true) {
File[] newFiles = dir.listFiles();
if(newFiles.length != files.length) {
for(File f:newFiles) {
boolean flag = true;
for(File f2:files) {
if(f.getName().equals(f2.getName())) {
flag = false;
}
}
if(flag) {
System.out.println("新文件产生:"+f.getName()+" "+Tools.getFmtTime(f.lastModified()));
}
}
files = newFiles;
}
try {
sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
拷贝文件同时显示文件拷贝完成进度
中心说明:主要将显示拷贝进度的线程设置为拷贝文件线程的守护线程,特点在于当拷贝任务完成时,其守护线程(进度显示)线程也将停止。
涉及:setDaemon(true)调用该方法设置为守护线程,在那个线程里设置的就为哪个线程的守护线程。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.NumberFormat;
public class FileCopyByThread extends Thread{
private File source;
private File target;
/**文件总大小*/
private double totalSize;
/**当前已拷贝大小*/
private double currentSize;
public FileCopyByThread(File source, File target) {
super();
this.source = source;
this.target = target;
}
@Override
public void run() {
try(
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(target);
){
//获取文件的实际大小
totalSize = source.length();
byte[] b = new byte[1024];
int len = 0;
//int read() 读取一个字节,返回是字节内容
//int read(byte[] b) 将读取的数据装入字节数组,返回真实读取长度
System.out.println(getName()+"开始拷贝:"+source.getName());
//创建并启动进度监控的线程
ProgressListener pl = new ProgressListener();
//设置当前线程为守护线程
pl.setDaemon(true);
pl.start();
while((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
//每次循环类增已拷贝的字节
currentSize += len;
}
System.out.println(getName()+"拷贝完成!");
}catch (IOException e) {
e.printStackTrace();
}
}
/**
* 计算文件拷贝的线程
* @author mrchai
*/
class ProgressListener extends Thread{
@Override
public void run() {
while(true) {
//计算进度
double d = currentSize / totalSize;
//将浮点进度格式化为百分比
String progress = NumberFormat.getPercentInstance().format(d);
System.out.println("拷贝进度------->"+progress);
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
File source = new File("源文件");
File target = new File("目标文件");
//启动文件拷贝线程
new FileCopyByThread(source, target).start();
}
}
4个线程同步拷贝一个文件
中心说明:应用RandomAccessFile流可以自由设置其读取/写出的指针位置对文件分割拷贝。
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FileSpitCopy extends Thread{
private File source;
private File target;
private long start;
private long end;
public FileSpitCopy(File source, File target, long start, long end) {
super();
this.source = source;
this.target = target;
this.start = start;
this.end = end;
}
public void run() {
try (
RandomAccessFile read = new RandomAccessFile(source,"r");
RandomAccessFile write = new RandomAccessFile(target,"rw");
){
read.seek(start);
write.seek(start);
int count = 0;
byte[] b =new byte[1024];
int len = 0;
while((len = read.read(b)) != -1) {
write.write(b,0,len);
count += len;
if(count >= (end-start)&& !"t3".equals(getName())) {
break;
}
}
System.out.println(getName()+"拷贝长度--->"+count);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
File source = new File("源文件");
File target = new File("目标文件");
long item = source.length()/4;
for (int i = 0; i < 4; i++) {
FileSpitCopy fsc = new FileSpitCopy(source,target,i*item,(i+1)*item);
fsc.setName("t"+i);
fsc.start();
}
}
}
注意事项
1.在进行文件访问时,若传入的是目录路径则会提示拒绝访问导致访问失败。
2.在有关递归调用的方法定义是通常情况下返回值类型设置为void,少部分方法利用返回值,比如下例:
//fib(1)+fib(2)
public int fib(int n) {
if (n == 1 || n == 2) {
return 1;
}
return fib(n - 2) + fib(n - 1);
}