注:本文出自coder-pig
原文链接:http://blog.csdn.net/coder_pig/article/details/45248445
很快要到I/O流了,都是重要的内容,而且内容很多有难度的哦,如果是小花自己写不知能否坚持下去,感谢小猪的这些文章,他可是花了很多心思,整个人都老了一大截,希望大家能好好看看,不枉他老人家一片苦心。。。
本节引言:
兜兜转转,又回来写Java了,上一篇J2SE知识点归纳笔记(六)---Java常用类是上2014.4.14写的,时隔一年
又来重拾之前还没写完的系列了,前些天群里一个妹子反映她Java基础薄弱,然后抱怨在csdn上找不到J2SE的
系列教程,J2SE简单嘛,个个都懒得写...真的简单么?或许吧...今天刚写完论文初稿,也算稍微轻松了那么一点,
白天上班,晚上赶论文,痛苦的一个星期也算到头了...趁着临近周末,小猪也来动下笔墨吧,(*^__^*) 嘻嘻……
哪怕有一个读者,小猪也会坚持写下去的。好了,唠叨的废话就说到这。本节要学习的东西:
Java IO,一说到IO,估计大家第一时间想起的就是:流,输入输出流,字符流,字节流等等,是吧,但是本节先不讲
流,先来点开胃菜,介绍两个文件IO的类: File(文件类)与RandomAccessFile(随机访问文件类),开始本节内容~
ps:另外说下Java IO相关的类和接口都放在java.io包下,大家要养成查API的习惯哦~
本节正文:
1.File(文件类):
1)File类的定义:
描述文件的相关特性,比如:是否可读,可写,文件大小等特性的一个类
2)创建File类对象时要注意的地方:
答:首先我们要区分两个名词:"绝对路径"和"相对路径"
绝对路径——即完整的路径,比如:D:\MyCode\Java\FileDemo
相对路径——会在代码所在的地方生成,比如:res/jay.txt 就会在你代码的目录下成jay.txt文件
另外,还有注意一点,文件的路径与Windows下不同,"\"要写成'/'或者"\\"不然会报错的喔~
如果,你想保险点,让程序跨平台的话,比如在linux下就和Windows不一样的,Linux下是"/"
解决方法就是使用File给我们提供的两个常量,他们分别是:
File.separator: "\" File.pathSeparator:";"
如果我们是直接自己拼的话,在window下,在D盘下我们要创建一个Jay.txt文件要这样写:
File f=new File("D:\\Jay.txt"); 如果在Linux下呢?要写成 //
如果我们用使用上面的两个常量的话,我们无需理在什么系统下,直接:
String fileName="D:"+File.separator+"Jay.txt";
File f=new File(fileName);
打印下fileName:
好了,记得把这两个变量Mark下来哦~
3)File的常见方法:
1)判断文件或者目录是否存在: exists()
2)判断是否为目录: isDirectory()
3)判断是否为文件: isFile()
4)判断文件是否可读: canRead()
5)判断文件是否可写: canWrite()
6)判断文件是否隐藏: isHidden()
7)判断文件路径是否为绝对路径: isAbsolute()
8)判断文件路径是否相同: equals():返回true,false
compareTo():是否相等,相等返回0,小于返回负数,大于返回正数
9)获取文件的绝对路径: getAbsolutePath()
10)获取文件名称: getName()
11)获取文件大小: length()
12)获取文件最后被修改的时间 : lastModified()
13)获取文件的路径: getPath()
14)获取文件的上层文件的目录: getParent()
15)创建一个新文件: createNewFile()
16)创建一个新目录: mkdir()
17)删除文件或目录: delete()
18)修改文件的名称: renameTo(str)
19)修改文件为只读: setReadOnly()
20)修改最后的修改时间: setLastModified(long time)
4)File的使用示例:
①创建一个文件:
- public void newFile(String fileName)throws Exception
- {
- File f=new File(fileName);
- f.createNewFile();
- }
②删除一个文件:
- public void deleteFile(String fileName)
- {
- File f=new File(fileName);
- if(f.exists())f.delete();
- else System.out.println("文件不存在");
- }
③创建一个文件夹:
- public void newDir(String fileName)
- {
-
- File f=new File(fileName);
- f.mkdir();
- }
④删除文件夹
删除文件夹的方法和删除文件是一样的,都是调用delete( )方法,空文件夹可以直接删除,
但是有一点要注意的是,非空文件夹是不能直接删除的哦!!!我们需要先把里面的文件都
删除了,才能删除文件夹哦,那么现在我们要做的是,就是删除文件夹里的文件咯,如果
有几层怎么破?我们需要考虑这个问题,这里的话,如果我们使用递归的话,就很容易解决
这个问题了,代码如下:
- import java.io.File;
-
- public class RemoveDir {
- public static void main(String[] args) {
- File file = new File("D:\\Test");
- removeDir(file);
- }
-
- public static void removeDir(File file) {
- File[] files = file.listFiles();
- for (File f : files) {
- if (f.isDirectory())
- {
- removeDir(f);
- } else {
- f.delete();
- }
- }
-
- file.delete();
- }
- }
好吧,递归就是这么奇妙~
⑤判断路径是否为文件夹(目录):
- public boolean isDir(String fileName)
- {
- File f=new File(fileName);
- if(f.isDirectory()){
- "white-space:pre"> return true;
- "white-space:pre"> }
- return false;
- }
⑥遍历某文件夹下所有文件(文件名,包含隐藏文件):
- public void getAllFile1(String fileName) {
- File f = new File(fileName);
- String[] str = f.list();
- for (int i = 0; i < str.length; i++) {
- System.out.println(str[i]);
- }
- }
⑦遍历某文件夹下所有文件(包括完整路径,包含隐藏文件)
- public void getAllFile2(String fileName) {
- File f = new File(fileName);
- File[] str = f.listFiles();
- for (int i = 0; i < str.length; i++) {
- System.out.println(str[i]);
- }
- }
⑧遍历某目录下的全部文件(包含子目录,完整路径,隐藏文件)
还是用到我们的递归:
-
-
-
- public void getAllFile3(File file) {
- if(file != null){
- if(file.isDirectory()){
- File[] fileArray=file.listFiles();
- if(fileArray!=null){
- for (int i = 0; i < fileArray.length; i++) {
-
- getAllFile3(fileArray[i]);
- }
- }
- }
- else{
- System.out.println(file);
- }
- }
- }
5)学以致用的两个小例子:
①遍历某个文件夹下特定的文件
比如某个目录下的所有.zip文件,笔者的电脑下载了很多编程视频,
我们想遍历查看所有.zip的文件的名称:
核心是:判断是否为目录,文件名的筛选
好吧,下面我们就来实现吧:
-
-
-
- public static void getSpecificFile(File file, String suffix) {
- if (file != null) {
- if (file.isDirectory()) {
- File[] fileArray = file.listFiles();
- String name1 = file.getName();
- System.out.println("——————" + name1);
- if (fileArray != null) {
- for (int i = 0; i < fileArray.length; i++) {
-
- getSpecificFile(fileArray[i], suffix);
- }
- }
- } else {
- if (file.getName().toString().endsWith(suffix)) {
- System.out.print(" ");
- System.out.println(file
- .getName()
- .toString()
- .substring(
- 0,
- file.getName().toString().length()
- - suffix.length()));
- }
- }
- }
- }
调用方法处代码:
部分运行截图:
②批量文件命名:
比如我们写App的时候,下载了一大堆了素材图片:
而下载的时候:他们的文件名是这样的:
我们是想把他们作为头像的,我们想把他们改成head1.png,head2.png...这种文件名格式的,
难道我们一个个手动的去改么=-=,如果这些图标有上百个,改到什么时候呢?
学以致用,这里我们就来实现简单的批量文件名修改:
比如我们这里需要批量修改下述的图标:
代码实现:
-
-
-
-
- public static boolean changeFileNames(String fileName,String suffix)
- {
- File f = new File(fileName);
- if(!f.isDirectory())
- {
- return false;
- }
- int j = 0;
- File[] fs = f.listFiles();
- for(int i = 0;i < fs.length;i++)
- {
- String str = fs[i].getName();
- if(str.endsWith(suffix))
- {
- fs[i].renameTo(new File(fileName + File.separator +"head" + j +suffix));
- / System.out.println(fileName + File.separator +"head" + j +suffix);
- j++;
- }
- }
- return true;
- }
运行后:
好了,就是那么简单,是不是又有趣呢?这里并没有都是一些简单的东西,笔者可以根据自己的需要,
进行拓展,比如遍历文件后,生成另外的txt文件而不是直接打印到屏幕上等....
2.RandomAccessFile类
1)这个类是干嘛的?
随机访问文件类,其实和File的功能类似,都是用于操作文件,但是RandomAccessFile类
有seek( )方法来访问文件,可以从文件的任意位置读写文件,这个seek可以看做文件指针吧,
而这个类,我们用的最多的无疑是:Java多线程文件下载~
ps:其实这个小猪已经在Android入门之路的day 8写过了,这里就再贴一遍哈,别怪小猪偷懒哈,
另外这个多线程下载的话,文件小的话效果不大哦~比如下个1,2mb的东西....另外示例给的是
Tomact搭建的web空项目,要下载的东西丢到Webroot目录下即可,另外你可以可以直接改成
网上的一个下载链接~
我们都知道使用多线程下载文件可以更快地完成文件的下载,但是为什么呢?
答:因为抢占的服务器资源多,假设服务器最多服务100个用户,服务器中的一个线程对应一个用户
100条线程在计算机中并发执行,由CPU划分时间片轮流执行,加入a有99条线程下载文件,那么
相当于占用了99个用户资源,自然就有用较快的下载速度
ps:当然不是线程越多就越好,开启过多线程的话,app需要维护和同步每条线程的开销,这些开销
反而会导致下载速度的降低,另外还和你的网速有关!
多线程下载的流程
获取网络连接——本地磁盘创建相同大小的空文件——计算每条线程需从文件哪个部分开始下载,结束
——依次创建,启动多条线程来下载网络资源的指定部分
ps:这里直接用J2SE来完成多线程操作,直接建立一个工程,使用Junit运行指定方法即可
如果再Android下用单元测试有点麻烦,照顾一部分朋友,你直接new一个Java Project即可!
代码如下:
DownLoader.java
- package com.jay.test;
-
- import java.io.InputStream;
- import java.io.RandomAccessFile;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import org.junit.Test;
-
-
- public class Downloader {
-
- @Test
- public void download() throws Exception
- {
-
- String filename = "meitu.exe";
- String path = "http://10.13.20.32:8080/Test/XiuXiu_Green.exe";
-
- URL url = new URL(path);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(5000);
- conn.setRequestMethod("GET");
-
-
- int filelength = conn.getContentLength();
- System.out.println("要下载的文件长度"+filelength);
-
- RandomAccessFile file = new RandomAccessFile(filename, "rwd");
- file.setLength(filelength);
- file.close();
- conn.disconnect();
-
- int threadsize = 3;
-
- int threadlength = filelength % 3 == 0 ? filelength/3:filelength+1;
- for(int i = 0;i < threadsize;i++)
- {
-
- int startposition = i * threadlength;
-
- RandomAccessFile threadfile = new RandomAccessFile(filename, "rwd");
- threadfile.seek(startposition);
-
- new DownLoadThread(i,startposition,threadfile,threadlength,path).start();
- }
- int quit = System.in.read();
- while('q' != quit)
- {
- Thread.sleep(2000);
- }
- }
-
-
- private class DownLoadThread extends Thread {
-
-
- private int threadid;
- private int startposition;
- private RandomAccessFile threadfile;
- private int threadlength;
- private String path;
- public DownLoadThread(int threadid, int startposition,
- RandomAccessFile threadfile, int threadlength, String path) {
- this.threadid = threadid;
- this.startposition = startposition;
- this.threadfile = threadfile;
- this.threadlength = threadlength;
- this.path = path;
- }
-
- public DownLoadThread() {}
-
- @Override
- public void run() {
- try
- {
- URL url = new URL(path);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(5000);
- conn.setRequestMethod("GET");
-
- conn.setRequestProperty("Range", "bytes="+startposition+"-");
-
- if(conn.getResponseCode() == 206)
- {
- InputStream is = conn.getInputStream();
- byte[] buffer = new byte[1024];
- int len = -1;
- int length = 0;
- while(length < threadlength && (len = is.read(buffer)) != -1)
- {
- threadfile.write(buffer,0,len);
-
- length += len;
- }
- threadfile.close();
- is.close();
- System.out.println("线程"+(threadid+1) + "已下载完成");
- }
-
-
- }catch(Exception ex){System.out.println("线程"+(threadid+1) + "下载出错"+ ex);}
- }
-
- }
- }
运行截图:
如图,使用多线程完成了对文件的下载!双击exe文件可运行,说明文件并没有损坏!
注意事项:
①int filelength = conn.getContentLength(); //获得下载文件的长度(大小)
②RandomAccessFile file = new RandomAccessFile(filename, "rwd");
//该类运行对文件进行读写,是多线程下载的核心
③int threadlength = filelength % 3 == 0 ? filelength/3:filelength+1;
//计算每个线程要下载的量
④conn.setRequestProperty("Range", "bytes="+startposition+"-");
//指定从哪个位置开始读写,这个是URLConnection提供的方法
⑤//System.out.println(conn.getResponseCode());
//这个注释了的代码是用来查看conn的返回码的,我们前面用的都是200,
而针对多线程的话,通常是206,必要时我们可以通过调用该方法查看返回码!
⑥int quit = System.in.read();
while('q' != quit){Thread.sleep(2000);}
//这段代码是做延时操作的,因为我们用的是本地下载,可能该方法运行完了,而我们的
线程还没有开启,这样会引发异常,这里的话,让用户输入一个字符,如果是'q'的话就退出
代码下载:J2SEMulDownLoader.zip
最后说两句:
关于JavaIO中的File和RandowAccessFile就介绍这里了,
大家可以发挥自己的创造力,使用这两个类,实现自己想要的功能~
最后把File的东东都贴到一个工具类中,有需要的可以复制粘贴: