javaIO

JAVA IO

java.io.File类

java对文件和目录的操作

java.io.File类用于表示文件或者目录。

对于File类的对象的操作实际就为对存储介质中的文件和目录的操作。

File类的文件操作与操作系统平台无关。

  1. 构造方法

    public File(String pathname)以pathname为路径创建File对象。

  2. 常用属性

    public static final String separator: 存储当前系统的路径分隔符。UNIX:'/',Windows:'\'。为了跨平台文件路径应用这个属性代替。

  3. 访问属性的方法

    • public boolean canRead():判断文件是否可读

    • public boolean canWrite(): 判断文件是否可写

    • public boolean exits(): 判断文件是否存在

    • public boolean isDirectory():判断是否是目录

    • public boolean isFile(): 判断是否为文件

    • public boolean isHidden(): 判断文件是否隐藏

    • public long lastModified(): 返回最后修改的时间

    • public long length(): 返回文件以字节为单位的长度

    • public String getName():获取文件名

    • public String getPath():获取文件的路径

    • public String getAbsolutePath():获取此文件的绝对路径名。

    • public String getCanonicalPath():获取此文件的规范路径名。

    • public File getAbsoluteFile(): 得到绝对路径规范表示的文件对象。

    • public String getParent():得到文件的父目录路径名

    • public URL toURL():返回此文件的统一资源标识符名

      public static void main(String[] args) throws IOException {
          File file = new File("D:\IOTest\source.txt");//指定目录要存在改文件
          
          
      }
      
  4. 对文件的操作

    • public boolean createNewFile(): 不存在时常见此文件对象所代表的空文件。
    • public boolean delete():删除文件。必须目录为空才能删除
    • public boolean mkdir():创建此抽象路径指定的目录。
    • public boolean mkdirs(): 创建此抽象路径指定的目录,同时创建父目录
    • public boolean renameTo(File dest):重新命名为此抽象路径表示的文件
  5. 浏览目录中的文件和子目录方法

    • public String[] list(): 返回此目录中的文件和目录名的数组
    • public File[] listFiles(): 返回此目录中的文件和目录的File实例数组
    • public File[] listFiles(FilenameFilter filter): 返回此目录中满足指定过滤器的文件和目录
    public static void main(String[] args) throws IOException{
        File dir1 = new File("D:/IOTest/dir1");
        if (!dir1.exists()) dir1.mkdir();//不存在就创建
        File dir2 = new File(dir1, "dir2");//以dir1为父目录 名字为dir2
        
        File dir4 = new File(dir1, "dir3/dir4");//以dir1,dir3为父目录 创建名字为dir4的目录
        
        File file = new File(dir2, "test.txt");
        if (!file.exists()) file.createNewFile();//不存在就创建
        
        deleteAll(dir1);//删除目录
    }
    
    public static void deleteAll(File file){
        if (file.isFile()) {
            file.delete();//直接删除文件
            return;
        }
        //是目录 则递归删除子目录和子文件
    	File[] lists = file.listFile();
        
        for (int i = 0; i < lists.length; i++) {
            deleteAll(list[i]);//则递归删除子目录和子文件
        }
        System.out.println("删除目录:"+ file.getAbsolutePath());
        file.delete();
    }
    

java IO原理

从数据源读数据时就要开启一个到数据源的流。

方便处理数据的输入输出。

流式结构

  1. 按数据流向
    • 输入流:程序可能从中读取数据的流
    • 输出流:程序可能从中输出数据的流
  2. 按数据传输单位
    • 字符流:传输单位为字符
    • 字节流:传输单位为字节
  3. 按流的功能
    • 节点流:用于直接操作数据源的流
    • 过滤流:处理流,对一个已经存在流的连接和封装,读写功能更强大

java.io包中四种抽象流类:

  • 字节流:
    • InputStream
    • OutputStream
  • 字符流:
    • Reader
    • Writer

InputStream和OutputStream

  1. InputStream

    以字节为单位从数据源中读取数据

    • public abstract int read() throws IOException: 从输入流中读取数据的下一个字节,返回读到的字节值。流的末尾返回-1
    • public void close() throws IOException:关闭输入流并释放系统资源
  2. OutputStream

    以字节为单位向数据源写数据

    • public abstract void write(int b) throws IOException:将指定的字节写入输出流
    • public void write(byte[] b) throws IOException: 将b.length个字节从指定的byte数组写入此输出流
    • public void flush() throws IOException :刷新此输出流,并强制写出所有缓冲的输出字节
    • public void close() throws IOException:关闭输入流并释放系统资源

Reader和Writer

  1. Reader

    以字符为单位从数据源中读取数据

    • public abstract int read() throws IOException: 从输入流中读取数据的字符,返回读到的字符值。流的末尾返回-1
    • public void close() throws IOException:关闭输入流并释放系统资源
  2. Writer

    以字符为单位向数据源写数据

    • public abstract void write(int b) throws IOException:将指定的字符写入输出流
    • public void write(char[] cbuf) throws IOException: 写入字符数组
    • public void write(String str) throws IOException:写入字符串
    • public void flush() throws IOException :将缓冲数据全部写到目的地
    • public void close() throws IOException:先刷新再关闭

文件流

FileInputStream、FileOutputStream、FileReader、FileWriter四个文件流。

  1. FileInputStream、FileOutputStream

    import java.io.*
    
    public static void main(String[] args) {
    	FileInputStream fin = null;
    	
    	try {
    		// 第一步:创建一个FileInputStream对象
    		fin = new FileInputStream("D:\IOTest\source.txt");
    		System.out.println("可读取的字节数" + fin.available());
    		//第二步:按字节读数据,返回的是读到的字节
    		int i = read();
    		while(i != -1) {
    			System.out.println((char)i);
    			i = fin.read();
    		}
    	} catch (FileNotFoundException e) {
    		e.printStackTrace();
    	} catch (IOException e) {
    		e.printStackTrace();
    	} finally {
    		try {
    			if (null != fin)
    				fin.close();//关闭输入流
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		
    	}
    }
    

    Java字符采用Unicode,汉字占用两个字节,英文字符占一个用字节流读取会出乱码问题。

    import java.io.*
    
    public static void main(String[] args) {
    	FileInputStream out = null;
    	try {
    		//1.建立连接
    		out = new FileInputStream("D:\IOTest\source.txt");
    		//2.写数据
    		out.write("#");
    		out.write("hello word".getBytes());//字符串转换为字节数组
    		out.write("你好".getBytes());//字符串转换为字节数组
    		//3.刷新输出流
    		out.flush();
    	} catch (FileNotFoundException e) {
    		e.printStackTrace();
    	} catch (IOException e) {
    		e.printStackTrace();
    	} finally {
    		try {
    			if (null != out)
    				out.close();//关闭输入流
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    IO流类的close方法会释放占有的系统资源,用来操作二进制文件比较合适,图片,声音,视频等二进制文件。

  2. FileReader、FileWriter

    以字符为操作单位的文件输入流和文件输出流。

    常用于操作字符文本文件。

    //实现字符文本的复制
    import java.io.*
    
    public static void main(String[] args) {
    	FileReader fr = null;
    	FileWriter fw = null;
    	int c = 0;
    	
    	try {
    		fr = new FileReader("D:\IOTest\source.txt");
    		fw = new FileWriter("D:\IOTest\result.txt");
    		
    		while((c = fr.read()) != -1) {
    			fw.write(c);
    		}
    		fw.flush();
    	} catch (FileNotFoundException e) {
    		e.printStackTrace();
    	} catch (IOException e) {
    		e.printStackTrace();
    	} finally {
    		try {
    			if (null != fw)
    				fw.close();//关闭输入流
    			if (null != fr)
    				fr.close();//关闭输入流
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    为了更高的效率可以一次提取一个字节数组和写入一个字节数组。

    int length = 0;//字符串长度
    char []cbuf = new char[8192];
    while((length = fr.reader(cbuf)) != -1) {
        fw.write(cbuf, 0, length);//一次性写入
    }
    

缓冲流

为了提高读写速率,提供带缓冲功能的流类,内部创建一个缓冲区数组。读取数据时,先把数据填充到该内部缓冲区,然后再返回;在写入数据前先放到缓冲区再一次性写入到目标数据源。

  • BufferedInputStream 和 BufferedOutputStream:针对字节的缓冲输入和输出流
  • BufferedReader和BufferedWriter:针对字符的缓冲输入和输出流

属于过滤流,不直接操作数据源,是对直接操作数据源的节点流的一个包装。

//用缓冲流来改写字符文本复制功能
public static void main(String[] args) {
    BufferedReader br = null;
    BufferedReader bw = null;
    
    try {
        //创建缓冲流对象:是过滤流,是对节点流的包装
        br = new BufferedReader(new FileReader("D:\IOTest\source.txt"));
        bw = new BufferedWriter(new FileWriter("D:\IOTest\source.txt"));
        
        String str = null;
        while ((str = br.readLine()) != null) { // 每次读取一行字符
            bw.write(str); //一次写入一行字符串
            bw.newLine(); //写入行分隔符
        }
        bw.flush();
    }
}

关闭过滤流时会自动关闭所包装的底层节点流。

转换流

在字节和字符流之间转换。

InputStreamReader和OutputStreamWriter。

  1. InputStreamReader

    将字节流中读取到的字节按指定字符集解码成字符,需要和InputStream套接

    • InputStreamReader(InputStream in):使用默认字符集的InputStreamReader
    • InputStreamReader(InputStream in, String charsetName):使用指定字符集的InputStreamReader
  2. OutputStreamWriter

    将要写入字节流的字符按指定字符集编码成字节,需要和OutputStream套接

    • OutputStreamWriter(OutputStream in):使用默认字符编码的OutputStreamWriter
    • OutputStreamWriter(OutputStream out, String charsetName):使用指定字符编码的OutputStreamWriter
public static void main(String[] args) {
    System.out.println("输入信息:按e或exit退出");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
    try {
        while(s = br.readLine() != null) {
            if (s.equalsIgnoreCase("e")||s.equalsIgnoreCase("exit")) {
                System.out.println("安全退出!!");
                break;
            }
            System.out.println("-->:" + s.toUpperCase());
            System.out.println("输入信息:按e或exit退出");
        }
    } catch {//异常处理
        ...
    }
}

先把字节流包装成字符流,为了进一步提高效率,又把它包装成缓冲流。

数据流

为了方便操作java语言的基本数据类型的数据,可以使用数据流。

DataInputStream和DataOutputStream分别来读写出基本数据类型

  • public final boolean readBoolean(): 从输入流中读取一个布尔型的值。
  • public final byte readByte(): 从输入流中读取一个8位的字节
  • public final char readChar(): 读取一个16位的Unicode字符
  • public final float readFloat(): 读取一个32位的单精度浮点数
  • public final double readDouble(): 读取一个64位的双精度浮点数
  • public final short readShort(): 读取一个16位的短整数
  • public final int readInt(): 读取一个16位的短整数
  • public final long readLong(): 读取一个64位的长整数
  • public final void readFully(byte[] b): 从当前输入流中读取b.length个字节到该字节数组
  • public final void readFully(byte[] b, int off, int len): 从当前数据流中读取len个字节到字节数组
  • public final String readUTF(): 读取一个UTF格式字符组成的字符串
  • public int skipBytes(int n): 跳过n字节
public static void main(String[] args) {
    DataOutputStream dos = null;
    try {
        //创建连接到指定文件的数据输出流对象
        dos = new DataOutoutStream(new FileOutputStream("d:\IOTest\destData.dat"));
        dos.writeUTF("ab 中国");
        dos.writeBoolean(false);
        dos.writeLong(12345678L);
    }
}

打印流

PrintStream和PrintWriter都属于打印流,提供一系列的print和println方法,可以实现将基本数据类型的数据格式转换成字符串进行输出。

PrintStream和PrintWriter不会抛出IOException异常

public class void main(String[] args) {
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(new File("d:\IOTest\text.txt"));
    } catch(FileNotFoundException e) {
        e.printStackTrace();
    }
    //创建打印输出流,设置为自动刷新模式(写入换行或字节'
'都会刷新输出缓冲区)
    PrintStream ps = new PrintStream(fos, true);
    if (ps != null) {
        //把标准输出流(控制台输出)改成文件
        System.setOut(ps);
    }
    for (int i = 0; i <= 255; i++) {
        System.out.print((char)i);
        if (i % 50 == 0) {
            System.out.println();//换行
        }
    }
    ps.close();
}

对象流

ObjectOutputStream和ObjectInputStream类是用于存储和读取基本数据类型或对象的过滤流,可以把Java 的对象写入到数据源中,也能把对象从数据源中还原回来。

用ObjectOutputStream保存基本数据类型或对象的机制叫做序列化。

用ObjectInputStream读取基本数据类型或对象的机制叫做反序列化。

ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量,能被序列化的对象所对应的类必须实现java.io.Serializable这个标识性接口。

public class Student implements java.io.Serializable {
    private int id;
    private String name;
    private transient int age; //在序列化的时候不会被保存和读取
    public Student(){}
    public student(int id, int age, String name) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public int getId() {return id;}
    public int getAge() {return age;}
    public String toString() {return "id="+id ,",name="+name,",age="+age;}
}

//创建一个学生对象并序列化到一个文件objectSeri.dat

public static void main(String[] args) {
    ObjectOutputStream oos = null;
    try {
        // 创建连接到指定文件的对象输出流实例
        oos = new ObjectOutputStream(new FileOutputStream("D:\IOTest\objectSeri.dat"));
        oos.write(new Student(101, 22,"张三"));
        oos.flush(); //刷新输出流
        System.out.println("序列化成功");
    } catch ()//异常处理
}

//把指定文件中的数据反序列化回来,并打印输出它的信息
public static void main(String[] args) {
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream("D:\IOTest\objectSeri.dat"));
        Student stu = (Student) ois.readObject();//读取对象
        System.out.println(stu);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        ois.close();
    }
}

随机存取文件流

RandomAccessFile 是一个特殊的流类,它可以在文件的任何地方读取或写入数据。打开后可以进行只读操作或者读写操作。

在第二个参数指定操作方式: r,rw,rws,rwd.

RandomAccessFile in = new RandomAccessFile("d:\IOTest||music.wmv", "r");

RandomAccessFile inout = new RandomAccessFile("d:\IOTest||music.wmv", "rwd");

类似存在一个文件指针,该文件指针标志将要读写操作的下一个字节的位置, getFilePointer()方法可以返回文件指针的当前位置。seek方法可以将文件指针移动到文件内部的任意字节位置。

随机存取文件流只能操作磁盘文件,不能访问来自网络或内存映像的流。

RandomAccessFile类的多线程下载程序

import java.io.*
import java.net.*

public class MutiThreadDownloadTest{
	public static void main(String[] args) thorws IOException{
		String urlStr = "http://...sss.mp3" ;//资源地址
		URL url = new URL(urlStr);  //创建URL
		URLConnection con = url.openConnection(); //建立连接
		int contentLen = con.getContentLength(); //获取连接资源总长度
		int threadQut = 10; //线程数
		int subLen = contentLen / threadQut;// 每个线程要下载的大小
		int remainder = contenLen % threadQut; // 余数
        File destFile = new File("D:\IOTest\sss.mp3"); //目标文件
        
        for (int i = 0; i < threadQut; i++) {
        	int start = subLen * i; //从目标文件的start位置开始写入到end结束总共subLen个字节
        	int end = start + subLen - 1; 
        	if (i == threadQut - 1) { //最后一次要加上余数
        		end += remainder;
        	}
        	Thread t = new Thread(new DownloadRunnable(start, end, url, destFile));//开启一个新线程
        	t.start();//启动新线程
        }
	}
}

public class DownloadRunnale implements Runnable {
	private final int start;
	private final int end;
	private final URL srcURL;
	private final File destFile;
	private static final int BUFFER_SIZE = 8192; //缓冲区大小
    public DownloadRunnale(int start, int end, URL srcURL, FILE destFile){
    	this.start = start;
    	this.end = end;
    	this.srcURL = srcURL;
    	this.destFile = destFile;
    }
    public void run() {
    	System.out.println("Thread.currentThread().getName()" + "启动");
    	BufferedInputStream bis = null;
    	RandomAccessFile ras = null;
    	byte[] buf = new byte[BUFFER_SIZE];
    	URLConnection con = null;
    	try {
    		con = srcURL.openConnection();
    		con.setRequestProperty("Range","byte="+start+"-"+end);
    		
    		bis = new BufferedInputStream(con.getInpputStream());
    		ras = new RandomAccessFile(destFile,"rw");
    		ras.seek(start);
    		int len = -1;
    		while ((len = bis.read(buf)) != -1) {
    			ras.write(buf, 0, len);
    		}
    		System.out.println(Thread.currentThread().getName() + "下载完毕"); 
    	}
    }
}

原文地址:https://www.cnblogs.com/DengSchoo/p/12831649.html