黑马程序员——7.2.IO(File、Properties对象、打印流、流的分并与割合、对象的序列化、管道流)

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

File类

File类用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。

File对象可以作为参数传递给流的构造函数。

创建File对象

public static void consMethod()
{
    //可以将已有的和未出现的文件或者文件夹封装成对象。

    //创建File对象
    File f1 = new File("a.txt");

    //创建包含父路径的File对象
    File f2 = new File("c:\\abc","b.txt");

    //把抽象路径封装成File对象
    File d = new File("c:\\abc");

    //把抽象路径File对象传递给构造函数创建新的File对象
    File f3 = new File(d,"c.txt");

    //考虑到不同系统的兼容性问题,可以使用File.separator代替目录分隔符
    File f4 = new File("c:"+File.separator+"abc"+File.separator+"zzz"+File.separator+"a.txt");
}

File.separator是与系统有关的默认名称分隔符。在 UNIX 系统上,此字段的值为 ‘/’;在 Microsoft Windows 系统上,它为 ‘\’。

File对象的常用方法:
一、获取

import java.io.File;
import java.text.DateFormat;
import java.util.Date;

public class FileMethodDemo{
    public static void main(String[] args){
        getDemo();
      }

    public static void getDemo(){
        //创建File对象
        File file1 = new File("a.txt" );

        //创建带路径的File对象
        File file2 = new File("d:\\demo\\a.txt" );

        //获取File对象的名称
        String name = file2.getName();

        //获取File对象的绝对路径
        String absPath = file2.getAbsolutePath();

        //获取File对象的抽象路径(创建对象的封装的路径)
        String path2 = file2.getPath();

        //获取文件的字节数大小
        long len = file2.length();

        //获取文件的最后修改时间
        long time = file2.lastModified();

        //获取文件的父目录(创建对象时封装的父路径)
        //如果没有指定父目录,则返回 null
        String parent1 = file1.getParent();
        String parent2 = file2.getParent();

        //用自定义日期格式初始化最后修改文件的时间
        Date date = new Date(time);
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
        String str_time = df.format(date);
      }
}

二、创建和删除

import java.io.File;
import java.io.IOException;

public class FileMethodDemo{
    public static void main(String[] args) throws IOException {
        createAndDeleteDemo();
    }

    public static void createAndDeleteDemo() throws IOException {
        //创建File对象
        File file = new File("file.txt" );

        //使用File对象创建新文件
        //如果文件不存在,则创建,如果文件存在,则不创建
        boolean b1 = file.createNewFile();
        System.out.println( "b1 = " + b1);

        //使用delete方法删除File对象对应的文件或文件夹
        //使用delete方法删除文件夹的时候,如果文件夹中有文件,会删除失败
        boolean b2 = file.delete();
        System.out.println( "b2 = " + b2);

        //创建封装了路径的File对象
        File dir = new File("abc" );

        //创建封装了多级路径的File对象
        File dir = new File("abc\\ab\\cc" );

        //使用mkdir可以创建文件夹
        boolean b3 = dir.mkdir();
        System.out.println( "b3 = " + b3);

        //使用mkdirs可以创建多级文件夹
        boolean b3 = dir.mkdirs();
        System.out.println( "b4 = " + b4);

        //最里层目录被干掉,dir代表的是最里层的目录
        boolean b5 = dir.delete();
        }
    }

三、判断

import java.io.File;
import java.io.IOException;

public class FileMethodDemo{
       public static void main(String[] args) throws IOException {
            isDemo();
      }

    public static void isDemo() throws IOException {
        File f = new File("aaa.txt" );

        //判断File对象对应的文件或文件夹存不存在
        boolean b = f.exists();

        System.out.println( "b = " + b);

        if(!f.exists()){
            f.createNewFile();
            }

        //最好先判断是否存在
        if(f.exists()){

            //判断File对象对应的是不是文件
            System.out.println(f.isFile());

            //判断File对象对应的是不是文件夹
            System.out.println(f.isDirectory());
        }

        f = new File("aa\\bb" );

        f.mkdirs();
        if(f.exists()){
            System.out.println(f.isFile());
            System.out.println(f.isDirectory());
        }
    }
}

四、重命名

import java.io.File;
import java.io.IOException;

public class FileMethodDemo{
    public static void main(String[] args) throws IOException {
        renameToDemo();
      }

    public static void renameToDemo() throws IOException {

        //f1已存在
        File f1 = new File("d:\\code\\day21\\0.mp3" );

        //f2不存在
        File f2 = new File("d:\\code\\day21\\1.mp3" );

        //把f1文件重命名成f2
        boolean b = f1.renameTo(f2);

        System.out.println( "b = " + b);
      }
}

五、系统根目录和容量获取

import java.io.File;
import java.io.IOException;

public class FileMethodDemo{
    public static void main(String[] args) throws IOException {
        listRootsDemo();
    }

    public static void listRootsDemo() throws IOException {

        //获取系统根目录下的file对象数组
        File[] files = File.listRoots();

        //打印file对象数组
        for(File file : files){
            System.out.println(file);
        }

        //把D盘封装成File对象
        File file = new File("d:\\" );

        //获取D盘的剩余容量字节数大小
        System.out.println( "getFreeSpace:" + file.getFreeSpace());

        //获取D盘的全部容量字节数大小
        System.out.println( "getTotalSpace:" + file.getTotalSpace());

        //获取D盘已使用容量字节数大小
        System.out.println( "getUsableSpace:" + file.getUsableSpace());
          }
    }

六、获取目录下的文件及文件夹

import java.io.File;
import java.io.FilenameFilter;

public class FileListDemo{
    public static void main(String[] args){
        listDemo();
    }

    public static void listDemo(){

        File file = new File("c:\\" );

        //获取目录下所有对象名称,返回字符串数组(包含隐藏文件,目录下没有内容时返回的数组长度为0)
        //File对象中封装的必须是目录,否则会发生异常(访问系统级目录也会发生异常)
        String[] names = file.list();

        //打印名称
        for(String name : names){
            System.out.println(name);

        //使用自定义的规则获取需要的列表
        String[] names = dir.list(new FilterByJava());
    }
}

//自定义获取目录列表的规则,并实现FilenameFilter接口
class FilterByJava implements FilenameFilter{

    //实现接口中的accept方法,定义返回规则
    public boolean accept(File dir,String name){

        //符合规则返回真,否则返回假
        //这里文件名是".java"结尾的返回真
        return name.endsWith(".java" );
    }
}

七、其他方法

File file = new File("a.txt" );

//判断该文件或文件夹是否隐藏(文件必须存在)
file.isHidden();

Properties对象:

hashtable的子类,即具有Map的特性,可以存储键值对,还可以从流中加载跟输出键值对信息

集合中的键和值都是字符串类型

通常用于操作以键值对形式存在的配置文件

import java.util.*;

public class PropertiesDemo{
    public static void main(String[] args){
        propertiesDemo();
      }

    public static void propertiesDemo(){
        //创建一个Properties集合
        Properties prop = new Properties();

        //存储元素
        prop.setProperty( "zhangsan","10" );
        prop.setProperty( "lisi","20" );
        prop.setProperty( "wangwu","30" );
        prop.setProperty( "zhaoliu","40" );

        //修改元素
        prop.setProperty( "wangwu","26" );

        //取出所有元素
        //获取Properties的键集合
        Set<String> names = prop.stringPropertyNames();

        for(String name : names){

            //通过Properties的键获得值
            String value = prop.getProperty(name);

            System.out.println(name + ":" + value);
        }
    }
}

/*
记录应用程序运行次数。
如果使用次数已到,那么给出注册提示,并不要再运行程序
即应该有计数器,并有文件保存计数器信息
*/

import java.io.*;
import java.util.*;

public class PropertiesTest{
       public static void main(String[] args) throws IOException{
            getAppCount();
      }

      public static void getAppCount() throws IOException {

        //创建Properties对象
        Properties prop = new Properties();

        //创建记录次数的文件count.ini并与File对象关联起来
        File file = new File("count.ini");

        //文件不存在则创建
        if(!file.exists())
            file.createNewFile();

        //把文件输入字节流与File对象关联起来
        FileInputStream fis = new FileInputStream(file);

        //从输入流中读取键值对到Properties对象中
        prop.load(fis);

        //创建记录次数的变量count
        int count = 0;

        //从Properties对象中读取记录的次数(此时为字符串)
        String value = prop.getProperty("time");

        //如果文件中存在该键值
        if(value!=null)
        {
            //把该值转换成Int类型并赋给count
            count = Integer.parseInt(value);

            //如果超过指定次数则打印提示信息,
            if(count>=5)
            {
                System.out.println("您好,使用次数已到,拿钱!");
                return ;
            }
        }
        else{
            //让运行次数加1
            count++;

            //运行该程序
            appRun();
        }

        //在Proterties对象中存储新的次数键值对
        prop.setProperty("time",count+"");

        //把文件输出字节流与File对象关联起来
        FileOutputStream fos = new FileOutputStream(file);

        //把Properties对象的键值对写入到输出流中
        prop.store(fos,"");

        //输出流关闭时会先把数据刷新到文件中
        fos.close();

        fis.close();
    }

    public static void appRun(){
        System.out.println("软件来了!");
    }
}

打印流:

可以直接操作输入流和文件。

打印流为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
与其他输出流不同,打印流永远不会抛出IOException,它可以捕获自己的异常。
打印流打印的所有字符都使用平台的默认字符编码转换为字节。提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式

PrintStrean是写入一串8bit的数据的。
PrintWriter是写入一串16bit的数据的。
PrintStream主要操作byte流,而PrintWriter用来操作字符流。读取文本文件时一般用后者。

字节打印流:

PrintStream
构造函数可以接收的参数类型:

  1. file对象。File
  2. 字符串路径。String
  3. 字节输出流。OutputStream
    字符打印流:

PrintWriter
构造函数可以接收的参数类型:

  1. file对象。File
  2. 字符串路径。String
  3. 字节输出流。OutputStream
  4. 字符输出流,Writer。

/*
键盘写入数据到out.txt文件中
*/

import java.io.*;

class  PrintWriterDemo
{
    public static void main(String[] args) throws IOException
    {
        //标准键盘输入
        BufferedReader bufr = 
            new BufferedReader(new InputStreamReader(System.in));

        //把打印字符输出流与文件关联起来,构造函数的第二个参数设置true表示自动刷新
        PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);

        String line = null;
        //循环读取键盘输入的一行数据
        while((line=bufr.readLine())!=null)
        {
            //为over就结束循环
            if("over".equals(line))
                break;

            //否则把输入的数据转成大写
            out.println(line.toUpperCase());

            //不用刷新因为上面的true设置了自动刷新
            //out.flush();
        }

        out.close();
        bufr.close();
    }   
}

合并流

SequenceInputStream:对多个流进行合并。

/*
需求:将1.txt、2.txt、3、txt文件中的数据合并到一个文件中。
*/

import java.io.*;
import java.util.*;

public class SequenceInputStreamDemo{
    public static void main(String[] args) throws Exception {

        //创建ArrayList集合用来存储要合并的输入流
        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();

        //把要合并的输入流添加到ArrayList集合中
        for(int x = 1; x <= 3; x++){
            al.add( new FileInputStream(x + ".txt" ));
        }

        //获取ArrayList集合的迭代器
        final Iterator<FileInputStream> it = al.iterator();

        //获取ArrayList集合上的枚举
        Enumeration<FileInputStream> en = Collections.enumeration(al);

        /*
        //Collections工具类的enumeration方法核心代码:
        Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
            public boolean hasMoreElements(){
                return it.hasMoreElements();
            }

            public FileInputStream nextElement(){
                return it.next();
            }
        };*/

        //创建合并流并通过集合上的枚举初始化该流
        SequenceInputStream sis = new SequenceInputStream(en);

        //创建输出流并与要合并成的新文件关联起来
        FileOutputStream fos = new FileOutputStream("4.txt" );

        byte[] buf = new byte[1024];

        int len = 0;

        //一行行循环读取合并流的数据并写入到输出流中
        while((len = sis.read(buf)) != -1){
            fos.write(buf,0,len);   
        }

        //关闭输出流和合并流
        fos.close();
        sis.close();
    }
}

文件的分割

import java.io.*;
import java.util.*;

public class SplitFileDemo{

    private static final int SIZE = 1024*1024;

    public static void main(String[] args) throws IOException{
        File file = new File("0.mp3" );
        splitFile(file);
    }

    public static void splitFile(File file) throws IOException {

        //用输入流关联源文件
        FileInputStream fis = new FileInputStream(file);

        //定义一个1M的缓冲区
        byte[] buf = new byte[SIZE];

        //创建输出流
        FileOutputStream fos = null;

        int len = 0;
        int count = 1;

        //切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数,以方便于合并。
        //这个信息为了进行描述,使用键值对的方式,用到了properties对象。

        Properties prop = new Properties();

        //创建保存键值对的文件
        File dir = new File("c:\\partFiles" );
        if(!dir.exists())
            dir.mkdirs();

        //将输入流循环写入到缓冲区中,直到数据为空
        while((len = fis.read(buf)) != -1){

            //每读一次就把缓冲区中的数据写入到一个part文件中
            fos = new FileOutputStream(new File(dir,(count++) + ".part"));
            fos.write(buf,0,len);
            fos.close();
        }

        //将被切割文件的信息保存到prop集合中
        prop.setProperty( "partcount",count + "" );
        prop.setProperty( "filename",file.getName());

        fos = new FileOutputStream(new File(dir,count + ".properties" ));

        //将prop集合中的数据存储到文件中
        prop.store(fos, "save file info");

        fis.close();
        fos.close();
    }
}

对象的序列化:

序列化堆内存中的对象
Serializable接口:要序列化对象必须要实现Serializable接口,接口中没有方法,会赋予对象一个UID号(long型的值),只是一个标记接口。

import java.io.*;

class ObjectStreamDemo 
{
    public static void main(String[] args) throws Exception
    {
        //writeObj();
        readObj();
    }

    public static void readObj()throws Exception
    {

        //创建对象输入流对象并关联obj.txt文件
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));

        //从该流中读取对象并转换成Person对象
        Person p = (Person)ois.readObject();

        System.out.println(p);
        ois.close();
    }
    public static void writeObj()throws IOException
    {
        //创建对象输出流对象并关联obj.txt文件
        ObjectOutputStream oos = 
            new ObjectOutputStream(new FileOutputStream("obj.txt"));

        //把Person对象写出到流中
        oos.writeObject(new Person("lisi0",399,"kr"));
        oos.close();
    }
}

静态不能被序列化,因为静态成员在方法区中
加上修饰符transient的成员也无法被序列化
自定义UID:任意修饰符+static final long serialVersionUID = 42L;

管道流:

PipedInputStream、PipedOutputStream
直接连接输入输出流,一般使用多线程,单线程容易造成死锁

import java.io.*;
class Read implements Runnable
{
    private PipedInputStream in;
    Read(PipedInputStream in)
    {
        this.in = in;
    }
    public void run()
    {
        try
        {
            byte[] buf = new byte[1024];
            System.out.println("读取前。。没有数据阻塞");

            //等待输出流的数据输入,这是阻塞式方法,获取数据会存储到buf中
            int len = in.read(buf);

            System.out.println("读到数据。。阻塞结束");
            String s= new String(buf,0,len);
            System.out.println(s);
            in.close();
        }
        catch (IOException e)
        {
            throw new RuntimeException("管道读取流失败");
        }
    }
}
class Write implements Runnable
{
    private PipedOutputStream out;
    Write(PipedOutputStream out)
    {
        this.out = out;
    }
    public void run()
    {
        try
        {
            System.out.println("开始写入数据,等待6秒后。");
            Thread.sleep(6000);

            //往输出流写入的数据会被输入流读取
            out.write("piped lai la".getBytes());
            out.close();
        }
        catch (Exception e)
        {
            throw new RuntimeException("管道输出流失败");
        }
    }
}
class  PipedStreamDemo
{
    public static void main(String[] args) throws IOException
    {

        //创建输入流跟输出流对象
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();

        //把输入流跟输出流连接起来
        in.connect(out);

        Read r = new Read(in);
        Write w = new Write(out);
        new Thread(r).start();
        new Thread(w).start();
    }
}

RandomAccessFile:

具备读和写功能,内部封装了数组,通过指针操作
内部封装了输入及输出流,只能操作文件
如果模式为只读r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

class RandomAccessFileDemo 
{
    public static void main(String[] args) throws IOException
    {
        //writeFile_2();
        //readFile();
        //System.out.println(Integer.toBinaryString(258));
    }
    public static void readFile()throws IOException
    {
        //创建对象关联文件,模式为只读
        RandomAccessFile raf = new RandomAccessFile("ran.txt","r");

        //调整对象中指针到第8个二进制位(从0开始),即从第二个字节开始读起。
        //raf.seek(8*1); 

        //跳过指定的字节数
        raf.skipBytes(8);
        byte[] buf = new byte[4];

        //读取数据到buf中,一次读buf.length个字节
        raf.read(buf);
        String name = new String(buf);

        //直接读32位整数,即读4个字节
        int age = raf.readInt();
        System.out.println("name="+name);
        System.out.println("age="+age);
        raf.close();
    }
    public static void writeFile_2()throws IOException
    {
        RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
        raf.seek(8*0);

        //写入byte数据
        raf.write("周期".getBytes());

        //写入4个字节的int数据
        raf.writeInt(103);
        raf.close();
    }
    public static void writeFile()throws IOException
    {
        RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");

        raf.write("李四".getBytes());
        raf.writeInt(97);
        raf.write("王五".getBytes());
        raf.writeInt(99);
        raf.close();
    }
}

DataStream基本数据类型流:

用于操作基本数据类型

import java.io.*;
class DataStreamDemo 
{
    public static void main(String[] args) throws IOException
    {
        //writeData();
        //readData();
        //writeUTFDemo();
//readUTFDemo();
    }
    public static void readUTFDemo()throws IOException
    {
        DataInputStream dis = new DataInputStream(new FileInputStream("utfdate.txt"));

        //使用UTF的编码方式读取一个字符。
        String s = dis.readUTF();
        System.out.println(s);
        dis.close();
    }

    public static void writeUTFDemo()throws IOException
    {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));

        //写入一个UTF-8编码的字符串
        dos.writeUTF("你好");
        dos.close();
    }
    public static void readData()throws IOException
    {
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

        //可以直接读取基本数据类型
        int num = dis.readInt();
        boolean b = dis.readBoolean();
        double d = dis.readDouble();
        System.out.println("num="+num);
        System.out.println("b="+b);
        System.out.println("d="+d);
        dis.close();
    }
    public static void writeData()throws IOException
    {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

        //可以直接写入基本数据类型
        dos.writeInt(234);
        dos.writeBoolean(true);
        dos.writeDouble(9887.543);
        dos.close();
    }

ByteArrayInputStream:

用于操作字节数组的流对象
ByteArrayInputStream :在构造的时候,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭。
用流的读写思想来操作数据。

import java.io.*;
class ByteArrayStream 
{
    public static void main(String[] args) 
    {
        //数据源。直接连接字节数组
        ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());

        //数据目的,内部封装了可变长度的字节数组
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int by = 0;
        while((by=bis.read())!=-1)
        {
            bos.write(by);
        }

        //输出流中封装了数组
        System.out.println(bos.size());
        System.out.println(bos.toString());
    //  bos.writeTo(new FileOutputStream("a.txt"));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值