黑马程序员 Java基础 I/O技术

几乎所有的应用程序都需要数据,而数据怎么来的,不可能都是人工录入,所以我们要借助数据存储设备,最常见的存储设备有硬盘、网络,而IO就是指应用程序对这些数据存储设备的输入和输出。

而在计算机中,所以的数据都被转化成二进制数进行存储,而这些数据在操作的过程中是作为一个文件来体现,所以,在IO的前提要先提一个File类,这是IO的基础。


一、java.io.File


在Java中,对存储设备中的文件和目录进行了封装,用一个File类来代表存储设备中的文件和目录。所以操作一个File对象就等于操作存储设备的文件或目录。

一个File对象可以是一个文件,也可以是一个目录,创建File对象后,如果是目录,可以显示目录清单,新建或删除目录,如果是文件可以查询文件的属性和路径星系。

1、File类的构建

File(String pathname)

pathname可以使绝对路径,也可以是相对路径。相对路径,就是相对于Java系统属性的user.dri中的路径。也就是当前字节码运行的目录。

File(String parent,String filename)

parent是父目录,filename是不含路径的文件名

File(File parent,String filename)

跟上面方法一样,不过parent由一个File对象提供

public class FileTest {
	
	public static void main(String[] args){
		//创建当前目录
		File dir1=new File(".");
		//创建上级目录
		File dir2=new File("..");
		//当前目录创建haha文件
		File test1=new File(dir1,"haha");
		File test2=new File(dir2,"haha.txt");
		System.out.println(dir1);
		System.out.println(dir2.exists());
		System.out.println(test1.exists());
		System.out.println(test2.exists());
		
	}
File类也给我们提供了很多方法来进行操作,其中很多访问和判断的方法,还有少部分创建和删除的方法。

public static void printProperties(File file){
		
		//getName()方法,获取文件或目录名
		System.out.println("name"+file.getName());
		//getPath()方法,获取文件路径
		System.out.println("name"+file.getPath());
		//getAbsolutePath()方法,获取绝对路径
		System.out.println("name"+file.getAbsolutePath());
		//isDirectory()是否目录
		System.out.println("name"+file.isDirectory());
		//isFile()是否文件
		System.out.println("name"+file.isFile());
		
	}	
File类里面提供了很多的方法,但是我们不用死记硬背,把绝对路径和相对路径,文件和目录的区别这几个概念搞清楚了,File类就基本掌握了,不记得可以查阅api文档。

虽然File给我们提供了很多的方法,但File不能操作文件里面的二进制数据,所以,我们就需要IO技术。


二、Java IO技术


java中的流就是数据的传输通道,程序需要数据,可以通过读取流从键盘,存储设备读取,当数据需要存储,可以通过输出流存储到设备中。

流根据传输单位来分可以分为字节流和字符流。

字节流可以操作任何数据,而字符流可以更方便的操作字符数据。

1、InputStream\OutputSteam

从上图可以看出,InputStream是所有字节输入流的超类。而字节输入流分不同的操作对象而分成不同的字节流。其中有一个很特殊FilterInputStream是专门接受流对象,从而增加一些功能。

同理,OutputStream是所有字节输出流的超类。而字节输出流分不同的操作对象而分成不同的字节流。FilterOutputStream是专门接受流对象,从而增加一些功能。

因为他们都是抽象类,所以,要创建对象就要根据需求用他们的子类来创建对象。

1、操作文件

有一个流的子类专门用于操作文件的,就是FileInputStream和FileOutputStream,到底他们怎么用下面有个例子。

public static void main(String[] args)throws Exception{
		File text=new File(".","text.txt.txt");
		File a1=new File(".","a.txt");
		a1.createNewFile();
		
	   InputStream bin=new FileInputStream(text);
		OutputStream bos=new FileOutputStream(a1);
		int a2=0;
		
		
		a2=bin.read();
		bos.write(a2);
		bos.flush();
		
		bin.close();
		bos.close();
		System.out.println();
	}
有几点需要注意,构建流需要try{}catch来构建,因为流容易发生不同的异常,还有输入流的文件必须要存在,否则报异常,输出流每次写完都要用flush()来刷新。

2、缓冲流

缓冲流并不操作数据,它只是一个增强功能的类,也称作过滤流。所以它操作的对象是其他数据流对象。

	public static void main(String[] args)throws Exception{
		File text=new File(".","text.txt.txt");
		File a1=new File(".","a.txt");
		a1.createNewFile();
		
	   BufferedInputStream bin=new BufferedInputStream(new FileInputStream(text));
		BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(a1));
		int a2=0;
		
		
		a2=bin.read();
		bos.write(a2);
		bos.flush();
		
		bin.close();
		bos.close();
		System.out.println();
	}

}

其实这个例子缓冲流就是增强了上面文件流的处理效率,它是一个增强行的中转站。

3、转换流

InputStreamReader和 OutputStreamWriter

它们是字节流转换成字符流的通道。

这里就先理解一下字符流。下面有张图。

字符流和字节流基本是一样的,不过字符流里面有一种参照的码表,会自动对应码表上的数字把字节数字转换成字符。

而更专业的就有转换流,它是直接告诉你我是把字节转换成字符,而且你可以直接指定码表。

他们对应的类就是InputStreamReader和 OutputStreamWriter。

public class IoTest {
	
	
		 public static void main(String[] args){  
		        BufferedReader bfr = null;  
		        BufferedWriter bfw = null;  
		        try{  
		            //System.in就是键盘录入
		            bfr = new BufferedReader(new InputStreamReader(System.in));  
		            //输出控制台
		            bfw = new BufferedWriter(new OutputStreamWriter(System.out));  
		            String line = null;  
		            while((line=bfr.readLine())!=null){  
		               
		                if("over".equals(line))  
		                    break;  
		                bfw.write(line.toUpperCase());  
		                bfw.newLine();  
		                bfw.flush();  
		            }  
		        }catch (IOException e){  
		            throw new RuntimeException("读写失败。");  
		        }  
		        finally{  
		            try{  
		                if(bfr!=null)  
		                    bfr.close();  
		            }catch (IOException e){  
		                throw new RuntimeException("读取流关闭失败。");  
		            }  
		            try{  
		                if(bfw!=null)  
		                    bfw.close();  
		            }catch (IOException e){  
		                throw new RuntimeException("写入流关闭失败。");  
		            }  
		        }  
		    }  
	}
字符流涉及到编码和解码,编码解码要用同一张表才能正确显示数据。

其实流的应用并不复杂,明白了源、目的、还有操作的数据类型,需要的方式,就会潜意识的选择不同的流来处理。

关于流还有一个比较强大的处理文件的类RandomAccessFile,这个类它可以读也可以写,而且可以根据不同的数据类型来读写,它里面有一个大型的Byte数组,

而且有一个指针,可以指定从哪里读起,也可以指定在哪个位置写,非常好用。下面是毕老师让我们模拟一个多线程下载的作业。

public class ClassTest {

        public static void main(String[] args)throws Exception {
                //这是源文件
                File f=new File("e:"+File.separator+"gjqt2_movie02.mp4");
                //这是复制的路径
                File k=new File("d:"+File.separator+"copy3.mp4");
                k.createNewFile();
                //每个线程用50M来分割
                long spilt=1024*1024*50;
                //求出线程数量
                int threadNum=(int)(f.length()/spilt);
                System.out.println(threadNum+1);
                //通过循环建立线程
                for(int x=0;x<=threadNum;x++)
                new Thread(new ThreadDownload(x,f,k)).start();
                
                
                
        }

}

class ThreadDownload implements Runnable{
        
        int account;
        int num=1;
        File fread=null;
        File fwrite=null;
        
        RandomAccessFile fr=null;
        RandomAccessFile fw=null;
        ThreadDownload(int account,File fread,File fwrite)
        {
                this.account=account;
                this.fread=fread;
                this.fwrite=fwrite;
        }
        
        public void run(){
                
                try{
                        
                        RandomAccessFile fr=new RandomAccessFile(fread,"r");
                        
                        RandomAccessFile fw=new RandomAccessFile(fwrite,"rw");
                        
                        fr.seek(1024*1024*50*account);
                        fw.seek(1024*1024*50*account);
                        
                
                        byte[] buf=new byte[1024*1024];
                        int length=0;
                        while(num<=50&&(length=fr.read(buf))!=-1)
                        {
                                num++;
                                fw.write(buf,0,length);
                                buf=new byte[1024*1024];
                        }
                }
                catch(Exception e)
                {
                        throw new RuntimeException("下载失败");
                }
                finally
                {
                        try{
                                if(fr!=null)
                                        fr.close();
                        }
                        catch(Exception e)
                        {
                                throw new RuntimeException("读取关闭失败");
                        }

                        try{
                                if(fw!=null)
                                        fw.close();
                        }
                        catch(Exception e)
                        {
                                throw new RuntimeException("写入关闭失败");
                        }
                        
                }
        }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值