黑马程序员--IO(二)--File类、Properties类、打印流、序列流等
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、File类
File类用来将文件或文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。File对象可以作为参数传递给流的构造函数。一旦创建,File对象表示的抽象路径名将永不改变。
- //封装对象的方式:可以将已存在或不存在的文件或目录封装成file对象。
- import java.io.File;
- class FileDemo
- {
- public static void main(String[] args)
- {
- constructorDemo();
- }
- public static void constructorDemo()
- {
- //方式一:
- File f1 = new File("d:\\demo\\a.txt");
- //方式二:
- File f2 = new File("d:\\demo","a.txt");
- //方式三:
- File f = new File("d:\\demo");
- File f3 = new File(f,"a.txt");
- //跨系统方式.File.separator是与系统有关的默认名称分隔符。UNIX系统上值为'/';
- File f4 = new File("d:"+File.separator+"demo"+File.separator+"a.txt");
- }
- }
//封装对象的方式:可以将已存在或不存在的文件或目录封装成file对象。
import java.io.File;
class FileDemo
{
public static void main(String[] args)
{
constructorDemo();
}
public static void constructorDemo()
{
//方式一:
File f1 = new File("d:\\demo\\a.txt");
//方式二:
File f2 = new File("d:\\demo","a.txt");
//方式三:
File f = new File("d:\\demo");
File f3 = new File(f,"a.txt");
//跨系统方式.File.separator是与系统有关的默认名称分隔符。UNIX系统上值为'/';
File f4 = new File("d:"+File.separator+"demo"+File.separator+"a.txt");
}
}
PS:流只能操作数据。
1、常见方法:
1.1 创建
boolean creatNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。只能创建一级文件夹。
boolean mkdirs():创建多级文件夹
1.2 删除
boolean delete():删除文件或目录。文件存在,返回true。文件不存在或正在被执行,返回false。
void deleteOnExit():在程序退出时删除指定文件。避免程序异常时,删除动作执行不到的问题。
1.3 判断
boolean canExecute():测试程序是否可以执行此路径名表示的文件。
boolean exists():判断文件是否存在。
boolean isDirectory():判断路径名是否是目录(文件夹)。
boolean isFile():判断路径名是否是文件。
boolean isHidden():判断路径名是否是一个隐藏文件。
boolean isAbsolute():判断路径名是否是绝对路径名。
PS:
判读文件对象是否是文件或目录时,必须要判断该文件对象封装的内容是否存在。
1.4 获取信息。
String getName():获取文件名。
String getPath():获取文件的相对路径。即创建的对象传入的参数是什么就获取到什么。
String getParent():返回文件绝对路径中的父目录。若获取相对路径,有明确父目录时,返回父目录,否则返回null。
String getAbsolutePath():获取文件的绝对路径。
long lastModified():返回文件最后一次被修改时间。判断文件是否被修改过。
long length():返回文件长度。
- //File类常见方法:
- import java.io.*;
- class FileDemo1
- {
- public static void main(String[] args) throws IOException
- {
- method_create();
- method_delete();
- method_judge();
- method_get();
- method_list();
- }
- public static void method_create() throws IOException
- {
- File f = new File("file.txt");
- //指定位置创建文件。因为它调用、启用资源有产生异常的可能。
- sop("create:"+f.createNewFile());
- File dir1 = new File("abc");
- //创建一级文件夹
- sop("mkdirs:"+dir1.mkdir());
- File dir2 = new File("abc\\a\\aad\\e");
- //创建多级文件夹
- sop("mkdirs:"+dir2.mkdirs());
- }
- public static void method_delete() throws IOException
- {
- File f = new File("a.txt");
- //删除文件或目录。文件存在,返回true。文件不存在或正在被执行,返回false。
- sop("delete:"+f.delete());
- //在程序退出时删除指定文件。
- File f2 = new File("file.txt");
- f2.deleteOnExit();
- }
- public static void method_judge() throws IOException
- {
- File f = new File("d:\\Demo\\IO3\\FileDemo\\file.txt");
- sop("canExecute:"+f.canExecute());
- //如果流存在才可以读写,所以exists方法可以直接判断流存在问题。
- sop("exists:"+f.exists());
- f.mkdir();
- //当判断文件对象是否是文件或目录时,必须要先判断该文件对象封装的内存是否存在。
- sop("dir:"+f.isDirectory());
- sop("file:"+f.isFile());
- sop("hidden:"+f.isHidden());
- sop(f.isAbsolute());
- }
- public static void method_get() throws IOException
- {
- File f = new File("d:\\a.txt");
- sop("path:"+f.getPath());
- sop("abspath:"+f.getAbsolutePath());
- sop("parent:"+f.getParent());
- sop("length:"+f.length());
- }
- public static void method_list() throws IOException
- {
- File f1 = new File("d:\\helloworld.java");
- File f2 = new File("d:\\a.java");
- //列出可以文件系统根目录
- sop("root"+f2.listRoots());
- //列出当前目录下所有文件
- sop("list"+f2.list());
- sop("rename:"+f1.renameTo(f2));
- }
- public static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
//File类常见方法:
import java.io.*;
class FileDemo1
{
public static void main(String[] args) throws IOException
{
method_create();
method_delete();
method_judge();
method_get();
method_list();
}
public static void method_create() throws IOException
{
File f = new File("file.txt");
//指定位置创建文件。因为它调用、启用资源有产生异常的可能。
sop("create:"+f.createNewFile());
File dir1 = new File("abc");
//创建一级文件夹
sop("mkdirs:"+dir1.mkdir());
File dir2 = new File("abc\\a\\aad\\e");
//创建多级文件夹
sop("mkdirs:"+dir2.mkdirs());
}
public static void method_delete() throws IOException
{
File f = new File("a.txt");
//删除文件或目录。文件存在,返回true。文件不存在或正在被执行,返回false。
sop("delete:"+f.delete());
//在程序退出时删除指定文件。
File f2 = new File("file.txt");
f2.deleteOnExit();
}
public static void method_judge() throws IOException
{
File f = new File("d:\\Demo\\IO3\\FileDemo\\file.txt");
sop("canExecute:"+f.canExecute());
//如果流存在才可以读写,所以exists方法可以直接判断流存在问题。
sop("exists:"+f.exists());
f.mkdir();
//当判断文件对象是否是文件或目录时,必须要先判断该文件对象封装的内存是否存在。
sop("dir:"+f.isDirectory());
sop("file:"+f.isFile());
sop("hidden:"+f.isHidden());
sop(f.isAbsolute());
}
public static void method_get() throws IOException
{
File f = new File("d:\\a.txt");
sop("path:"+f.getPath());
sop("abspath:"+f.getAbsolutePath());
sop("parent:"+f.getParent());
sop("length:"+f.length());
}
public static void method_list() throws IOException
{
File f1 = new File("d:\\helloworld.java");
File f2 = new File("d:\\a.java");
//列出可以文件系统根目录
sop("root"+f2.listRoots());
//列出当前目录下所有文件
sop("list"+f2.list());
sop("rename:"+f1.renameTo(f2));
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
1.5 列出文件及文件过滤static File[] listRoots():列出可用的文件系统根目录,即系统盘符。
String[] list():列出当前目录下所有文件,包括隐藏。调用list方法的file对象必须是封装了一个已存在的目录。
String[] list(FilenameFilter filter):返回一个字符串数组,获取目录中满足指定过滤器的文件和目录。
FilenameFilter:文件名过滤器,是一个接口,其中包含一个方法:accept(File dir,String name),返回的是boolean。
File[] listFiles():返回一个抽象路径名数组,获取当前文件夹下的所有文件和文件夹。
boolean renameTo(File dest):重命名。
list和listFiles区别:
list返回当前目录下的文件和名称;listFiles返回当前目录下的文件和文件对象。
即list只能获取名,listFiles可以通过方法获取更多属性。
- //list方法
- import java.io.*;
- class FileDemo2
- {
- public static void main(String[] args)
- {
- listRootsDemo();
- listDemo();
- listDemo_2();
- listfileDemo();
- }
- public static void listfileDemo()
- {
- File dir = new File("D:\\Demo\\IO3");
- File[] files = dir.listFiles();
- for(File f:files)
- {
- System.out.println(f.getName()+"::"+f.length());
- }
- }
- public static void listDemo_2()
- {
- File dir = new File("D:\\Demo\\IO3");
- String[] arr = dir.list(new FilenameFilter()
- {
- //list依据accept的返回值来判断数组内容。
- public boolean accept(File dir,String name)
- {
- return name.endsWith(".txt");
- }
- });
- System.out.println("len:"+arr.length);
- for(String name:arr)
- {
- System.out.println(name);
- }
- }
- public static void listDemo()
- {
- File f = new File("D:\\");
- //调用list方法的file对象必须是封装了一个目录。该目录必须存在。
- String[] names = f.list();
- for(String name:names)
- {
- System.out.println(name);
- }
- }
- //打印系统有效盘符。
- public static void listRootsDemo()
- {
- File[] files = File.listRoots();
- for(File f:files)
- {
- System.out.println(f);
- }
- }
- }
//list方法
import java.io.*;
class FileDemo2
{
public static void main(String[] args)
{
listRootsDemo();
listDemo();
listDemo_2();
listfileDemo();
}
public static void listfileDemo()
{
File dir = new File("D:\\Demo\\IO3");
File[] files = dir.listFiles();
for(File f:files)
{
System.out.println(f.getName()+"::"+f.length());
}
}
public static void listDemo_2()
{
File dir = new File("D:\\Demo\\IO3");
String[] arr = dir.list(new FilenameFilter()
{
//list依据accept的返回值来判断数组内容。
public boolean accept(File dir,String name)
{
return name.endsWith(".txt");
}
});
System.out.println("len:"+arr.length);
for(String name:arr)
{
System.out.println(name);
}
}
public static void listDemo()
{
File f = new File("D:\\");
//调用list方法的file对象必须是封装了一个目录。该目录必须存在。
String[] names = f.list();
for(String name:names)
{
System.out.println(name);
}
}
//打印系统有效盘符。
public static void listRootsDemo()
{
File[] files = File.listRoots();
for(File f:files)
{
System.out.println(f);
}
}
}
2、递归
2.1 定义
递归:函数自身调用自身的表现形式或编程手法。因为目录中还有目录,只有使用同一个
列出目录功能的函数完成即可。在列出过程中出现的还是目录的话,还可以再次调用本功能。
2.2 注意事项:
a 限定次数。
b 注意递归次数,避免内存溢出。因为每次调用自己都会执行下一次调用自己的方法,所以会不断
在栈内存中开辟新空间,次数过多,会导致内存溢出。
- /*
- 列出指定目录下文件或文件夹,包含子目录的内容。
- 因为目录中还有目录,只有使用同一个列出目录功能的函数完成即可。
- 在列出过程中出现的还是目录的话,还可以再次调用本功能。
- 也就是函数自身调用自身。
- 这种表现形式或编程手法,称为递归。
- 递归注意事项:
- 1,限定次数。
- 2,注意递归次数,避免内存溢出。
- */
- import java.io.*;
- class FileDemo3
- {
- public static void main(String[] args)
- {
- File dir = new File("D:\\Demo");
- showDir(dir);
- //int n = getSum(25000);
- //System.out.println(n);
- }
- //递归会不断开辟栈对象次数过多,有内存溢出风险。
- public static int getSum(int n)
- {
- if(n==1)
- return 1;
- return n+getSum(n-1);
- }
- //递归:自我调用。因为没有次数限制,会成为无限循环,失去价值。
- public static void method()
- {
- method();
- }
- public static void showDir(File dir)
- {
- //打印目录
- System.out.println(dir);
- File[] files = dir.listFiles();
- //递归
- for(int x=0; x<files.length; x++)
- {
- //如果文件中有文件夹,再次调用自己。
- if(files[x].isDirectory())
- showDir(files[x]);
- System.out.println(files[x]);
- }
- }
- }
/*
列出指定目录下文件或文件夹,包含子目录的内容。
因为目录中还有目录,只有使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是函数自身调用自身。
这种表现形式或编程手法,称为递归。
递归注意事项:
1,限定次数。
2,注意递归次数,避免内存溢出。
*/
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("D:\\Demo");
showDir(dir);
//int n = getSum(25000);
//System.out.println(n);
}
//递归会不断开辟栈对象次数过多,有内存溢出风险。
public static int getSum(int n)
{
if(n==1)
return 1;
return n+getSum(n-1);
}
//递归:自我调用。因为没有次数限制,会成为无限循环,失去价值。
public static void method()
{
method();
}
public static void showDir(File dir)
{
//打印目录
System.out.println(dir);
File[] files = dir.listFiles();
//递归
for(int x=0; x<files.length; x++)
{
//如果文件中有文件夹,再次调用自己。
if(files[x].isDirectory())
showDir(files[x]);
System.out.println(files[x]);
}
}
}
二、Properties类
Properties是hashtable的子类。所以它具备Map集合的特点。而且它存储的键值对都是字符串。无泛型定义。它是集合和IO技术集合的集合容器。
1、特点:
a 可以用于键值对形式的配置文件。
b 在加载数据时,需要数据有固定格式:键=值。
c 集合中的数据可以保存到流中或从流中获取。
2、特有方法:
2.1 设置
Object setProperty(String key,String value):设置键和值,调用Hashtable的方法put。
2.2 获取
String getProperty(String key):通过键获取值。
Set<String> stringPropertyNames():返回此属性列表中的键集。将map变成set,带泛型。
3.3 加载与存储
void load(InputStream ism):将字节流中的数据加载进集合。
void load(Reader reader):将字符流中的数据加载进集合。
void list(PrintStream out):将属性列表输出到指定的输出流中。
void store(OutputStream out,String comments):对应load(InputStream)将属性列表(键值对)写入输出流。comments注释信息。
void store(Writer writer,String comments):对应load(Reader)将属性列表(键值对)写入输出流。
- /*
- Properties类实例:
- 本文件解决问题:
- 1,设置和获取元素。
- 2,将流中的数据存储到集合中。
- 思路:
- 1,用一个流和info.txt文件关联。
- 2,读取一行数据,将该行数据用“=”进行切割。
- 3,等号左边作为键,右边作为值。存入到Properties集合中即可。
- */
- import java.io.*;
- import java.util.*;
- class PropertiesDemo
- {
- public static void main(String[] args) throws IOException
- {
- setAndGet();
- method_1();
- loadDemo();
- }
- public static void loadDemo() throws IOException
- {
- Properties prop = new Properties();
- FileInputStream fis = new FileInputStream("info.txt");
- //将流中的数据加载进集合
- prop.load(fis);
- //修改数据信息,但是无法改源文件。
- prop.setProperty("wangwu","39");
- FileOutputStream fos = new FileOutputStream("info.txt");
- //将属性列表(键值对)写入输出流。
- prop.store(fos,"haha");
- //System.out.println(prop);
- //另一种输出方式。
- prop.list(System.out);
- fos.close();
- fis.close();
- }
- //模拟load方法。将流中的数据存储到集合中。
- public static void method_1() throws IOException
- {
- BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
- String line = null;
- Properties prop = new Properties();
- while((line=bufr.readLine())!=null)
- {
- String[] arr = line.split("=");
- //将键值对存入Properties中
- prop.setProperty(arr[0],arr[1]);
- }
- bufr.close();
- System.out.println(prop);
- }
- //设置和获取元素。
- public static void setAndGet()
- {
- Properties prop = new Properties();
- //设置
- prop.setProperty("zhangsan","30");
- prop.setProperty("lisi","34");
- //System.out.println(prop);
- //获取
- String value = prop.getProperty("lisi");
- //System.out.println(value);
- //修改信息、
- prop.setProperty("lisi",98+"");
- //取出所有元素
- Set<String> names = prop.stringPropertyNames();
- for(String s : names)
- {
- System.out.println(s+":"+prop.getProperty(s));
- }
- }
- }
/*
Properties类实例:
本文件解决问题:
1,设置和获取元素。
2,将流中的数据存储到集合中。
思路:
1,用一个流和info.txt文件关联。
2,读取一行数据,将该行数据用“=”进行切割。
3,等号左边作为键,右边作为值。存入到Properties集合中即可。
*/
import java.io.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args) throws IOException
{
setAndGet();
method_1();
loadDemo();
}
public static void loadDemo() throws IOException
{
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("info.txt");
//将流中的数据加载进集合
prop.load(fis);
//修改数据信息,但是无法改源文件。
prop.setProperty("wangwu","39");
FileOutputStream fos = new FileOutputStream("info.txt");
//将属性列表(键值对)写入输出流。
prop.store(fos,"haha");
//System.out.println(prop);
//另一种输出方式。
prop.list(System.out);
fos.close();
fis.close();
}
//模拟load方法。将流中的数据存储到集合中。
public static void method_1() throws IOException
{
BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
String line = null;
Properties prop = new Properties();
while((line=bufr.readLine())!=null)
{
String[] arr = line.split("=");
//将键值对存入Properties中
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
}
//设置和获取元素。
public static void setAndGet()
{
Properties prop = new Properties();
//设置
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","34");
//System.out.println(prop);
//获取
String value = prop.getProperty("lisi");
//System.out.println(value);
//修改信息、
prop.setProperty("lisi",98+"");
//取出所有元素
Set<String> names = prop.stringPropertyNames();
for(String s : names)
{
System.out.println(s+":"+prop.getProperty(s));
}
}
}
应用:创建文件访问计数器。
- /*
- 需求:记录应用程序运行次数。如果使用次数已到,给出注册提示。
- 思路:
- 1、在程序中定义计数器,随着程序的运行存在并自增。但是普通计数器会随着程序退出而清0;
- 2、建立一个配置文件,记录该软件的使用次数。
- 3、为便于阅读、操作数据,该配置文件使用键值对的形式。
- 4、键值对数据是map集合;数据是以文件形式存储,使用io技术;那么map+io -->properties。
- 配置文件可以实现应用程序数据的共享。
- */
- import java.io.*;
- import java.util.*;
- class RunCount
- {
- public static void main(String[] args) throws IOException
- {
- Properties prop = new Properties();
- //将文件独立封装可以使用判读方法,防止文件不存在时抛出异常。
- File file = new File("count.ini");
- if(!file.exists())
- file.createNewFile();
- FileInputStream fis = new FileInputStream(file);
- prop.load(fis);
- int count = 0;
- String value = prop.getProperty("time");
- if(value!=null)
- {
- //将字符串转成基本数据类型。静态装换方法
- count = Integer.parseInt(value);
- if(count>=5)
- {
- System.out.println("使用次数已到,请充值!");
- return;
- }
- }
- count++;
- prop.setProperty("time",count+"");
- FileOutputStream fos = new FileOutputStream(file);
- prop.store(fos,"");
- fos.close();
- fis.close();
- }
- }
/*
需求:记录应用程序运行次数。如果使用次数已到,给出注册提示。
思路:
1、在程序中定义计数器,随着程序的运行存在并自增。但是普通计数器会随着程序退出而清0;
2、建立一个配置文件,记录该软件的使用次数。
3、为便于阅读、操作数据,该配置文件使用键值对的形式。
4、键值对数据是map集合;数据是以文件形式存储,使用io技术;那么map+io -->properties。
配置文件可以实现应用程序数据的共享。
*/
import java.io.*;
import java.util.*;
class RunCount
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();
//将文件独立封装可以使用判读方法,防止文件不存在时抛出异常。
File file = new File("count.ini");
if(!file.exists())
file.createNewFile();
FileInputStream fis = new FileInputStream(file);
prop.load(fis);
int count = 0;
String value = prop.getProperty("time");
if(value!=null)
{
//将字符串转成基本数据类型。静态装换方法
count = Integer.parseInt(value);
if(count>=5)
{
System.out.println("使用次数已到,请充值!");
return;
}
}
count++;
prop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(file);
prop.store(fos,"");
fos.close();
fis.close();
}
}
三、打印流
打印流:PrintStream、PrintWriter。可直接操作输入流和文件,将传入数据原样打印。1、PrintStream:字节打印流。为其他输出流添加打印各种数据值的功能。特点:不会抛出IOException。
PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。当需要写入字符时应使用PrintWriter类。
构造函数可以接收的参数类型:
1.1 File对象。File
1.2 字符串路径。String
1.3 字节输出流。OutputStream
2、PrintWriter:字符打印流。
构造函数可以接收的参数类型:
2.1 File对象。File
2.2 字符串路径。String
2.3 字节输出流。OutputStream
2.4 字符输出流。Writer。
- //打印流:提供打印方法,可以将各种数据类型的数据原样打印。
- import java.io.*;
- class PrintStreamDemo
- {
- public static void main(String[] args) throws IOException
- {
- PrintStream ps = new PrintStream("print.txt");
- //write(int b):只写最低8位。
- ps.write(97);//a
- //print方法原数打印
- ps.print(97);//97
- BufferedReader bufr =
- new BufferedReader(new InputStreamReader(System.in));
- //PrintWriter构造函数的第二个参数设置为true,表示自动刷新。
- PrintWriter pw = new PrintWriter(System.out,true);
- String line = null;
- while((line=bufr.readLine())!=null)
- {
- if("over".equals(line))
- break;
- pw.println(line.toUpperCase());//ln是刷新标记
- //pw.flush();
- }
- ps.close();
- pw.close();
- bufr.close();
- }
- }
//打印流:提供打印方法,可以将各种数据类型的数据原样打印。
import java.io.*;
class PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
PrintStream ps = new PrintStream("print.txt");
//write(int b):只写最低8位。
ps.write(97);//a
//print方法原数打印
ps.print(97);//97
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//PrintWriter构造函数的第二个参数设置为true,表示自动刷新。
PrintWriter pw = new PrintWriter(System.out,true);
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
pw.println(line.toUpperCase());//ln是刷新标记
//pw.flush();
}
ps.close();
pw.close();
bufr.close();
}
}
四、序列流
SequenceInputStream:序列流(合并流)。多源对应一个目的时,省去部分关联和续写步骤,简化代码。SequenceInputStream(InputStream s1, InputStreamS2 ): 依顺序读取s1,s2
SequenceInputStream(Enumeration<? extends InputStream> e):多个参数合并
- /*
- SequenceInputStream:序列流(合并流)。
- 需求:将1.txt、2.txt、3.txt合并为一个文件4.txt。
- */
- import java.io.*;
- import java.util.*;
- class SequenceDemo
- {
- public static void main(String[] args) throws IOException
- {
- Vector<FileInputStream> v = new Vector<FileInputStream>();
- v.add(new FileInputStream("D:\\1.txt"));
- v.add(new FileInputStream("D:\\2.txt"));
- v.add(new FileInputStream("D:\\3.txt"));
- Enumeration<FileInputStream> en = v.elements();
- //合并流,统一源。
- SequenceInputStream sis = new SequenceInputStream(en);
- //目的。
- FileOutputStream fos = new FileOutputStream("D:\\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();
- }
- }
/*
SequenceInputStream:序列流(合并流)。
需求:将1.txt、2.txt、3.txt合并为一个文件4.txt。
*/
import java.io.*;
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("D:\\1.txt"));
v.add(new FileInputStream("D:\\2.txt"));
v.add(new FileInputStream("D:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
//合并流,统一源。
SequenceInputStream sis = new SequenceInputStream(en);
//目的。
FileOutputStream fos = new FileOutputStream("D:\\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();
}
}
五、操作对象
操作对象:ObjectInputStream、ObjectOutputStream。ObjectOutputStream:将Java对象的基本数据类型和图形写入OutputStream。
被操作的对象需要实现Serializable接口才能使用序列化功能。
Serializable接口是标记接口,它用于给被序列化的类加入ID号,以判断类和对象是否是同一个版本。
静态不能被序列化,因为静态在方法区中,不在堆中。
serialVersionUID:给类定义固定标识,方便序列化。新类可以操作曾经被序列化的对象。
transient:是让非静态成员无法序列化的关键字。保证它的值在堆内存中存在,而不显示在文本文件中。
- /*
- 操作对象:ObjectInputStream、ObjectOutputStream
- NotSerializableException:某个要序列化的对象不能实现 java.io.Serializable 接口异常。
- */
- import java.io.*;
- class Person implements Serializable
- {
- //serialVersionUID:给类定义固定标识,使新类还可以用之前的序列化对象。
- public static final long serialVersionUID = 42L;
- private String name;
- transient int age;//不想非静态成员序列化加关键字:transient
- //静态不能被序列化,因为静态在方法区中,不在堆中。
- static String country = "cn";
- Person(String name,int age,String country)
- {
- this.name=name;
- this.age=age;
- this.country = country;
- }
- public String toString()
- {
- return name+":"+age+":"+country;
- }
- }
- class ObjectStreamDemo
- {
- public static void main(String[] args) throws Exception
- {
- writeObj();
- readObj();
- }
- public static void readObj() throws Exception
- {
- ObjectInputStream ois =
- new ObjectInputStream(new FileInputStream("obj.txt"));
- Person p = (Person)ois.readObject();
- System.out.println(p);
- ois.close();
- }
- public static void writeObj() throws IOException
- {
- //目的:将对象保存成文件
- ObjectOutputStream oos =
- new ObjectOutputStream(new FileOutputStream("obj.txt"));
- oos.writeObject(new Person("lisi0",339,"USA"));
- oos.close();
- }
- }
/*
操作对象:ObjectInputStream、ObjectOutputStream
NotSerializableException:某个要序列化的对象不能实现 java.io.Serializable 接口异常。
*/
import java.io.*;
class Person implements Serializable
{
//serialVersionUID:给类定义固定标识,使新类还可以用之前的序列化对象。
public static final long serialVersionUID = 42L;
private String name;
transient int age;//不想非静态成员序列化加关键字:transient
//静态不能被序列化,因为静态在方法区中,不在堆中。
static String country = "cn";
Person(String name,int age,String country)
{
this.name=name;
this.age=age;
this.country = country;
}
public String toString()
{
return name+":"+age+":"+country;
}
}
class ObjectStreamDemo
{
public static void main(String[] args) throws Exception
{
writeObj();
readObj();
}
public static void readObj() throws Exception
{
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("obj.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj() throws IOException
{
//目的:将对象保存成文件
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi0",339,"USA"));
oos.close();
}
}
PS:1 对象的实体化存储:将对象存储在硬盘上。也可称为对象的序列化、对象的可串联性。
2 标记接口:没有方法的接口。只是为了标识其信息。
六、RandomAccessFile
RandomAccessFile:随机访问文件,自身具备读写方法。它直接继承自Object,不算是IO体系中子类。1、特点:
1.1 具备读和写功能;
1.2 该对象内部封装了一个byte数组,并通过指针可以操作数组中的元素;
1.3 可以通过getFilePointer方法获取指针位置,通过seek方法改变指针位置。
1.4 该对象只能操作文件,而且操作文件还有模式:只读:r,读写:rw。
PS:
1 读写原理:内部封装了字节输入流和输出流。
2 操作文件模式:
如果模式为只读 r:不创建文件。只读取一个已存在的文件,如果该文件不存在,则会出现异常。
如果模式为读写rw:操作的文件不存在,会自动创建。如果存在不会覆盖。
2、常用方法:
skipBytes()跳过指定的字节数;
seek()调整对象中指针;
- //RandomAccessFile:随机访问文件。
- import java.io.*;
- class RandomAccessFileDemo
- {
- public static void main(String[] args) throws IOException
- {
- writeFile();
- readFile();
- writeFile_2();
- }
- public static void readFile() throws IOException
- {
- RandomAccessFile raf = new RandomAccessFile("ran.txt","r");//只读
- //通过seek访问任意位置。
- //raf.seek(8);
- //跳过指定的字节数。不能回跳
- raf.skipBytes(8);
- byte[] buf = new byte[4];
- raf.read(buf);
- String name = new String(buf);
- int age = raf.readInt();
- System.out.println("name="+name);
- System.out.println("age="+age);
- raf.close();
- }
- public static void writeFile() throws IOException
- {
- RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
- raf.write("Lisi".getBytes());
- //使用write方法写入最后一个字节。只取8位,超过256时存在数据丢失。
- raf.write(257);
- //使用writeInt方法写入四个字节(int类型)
- raf.writeInt(97);
- raf.write("wagnwu".getBytes());
- raf.writeInt(99);
- raf.close();
- }
- public static void writeFile_2() throws IOException
- {
- RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
- //往指定位置写入数据
- raf.seek(2*8);
- raf.write("周期".getBytes());
- raf.writeInt(103);
- raf.close();
- }
- }
//RandomAccessFile:随机访问文件。
import java.io.*;
class RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
writeFile();
readFile();
writeFile_2();
}
public static void readFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");//只读
//通过seek访问任意位置。
//raf.seek(8);
//跳过指定的字节数。不能回跳
raf.skipBytes(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name="+name);
System.out.println("age="+age);
raf.close();
}
public static void writeFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("Lisi".getBytes());
//使用write方法写入最后一个字节。只取8位,超过256时存在数据丢失。
raf.write(257);
//使用writeInt方法写入四个字节(int类型)
raf.writeInt(97);
raf.write("wagnwu".getBytes());
raf.writeInt(99);
raf.close();
}
public static void writeFile_2() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
//往指定位置写入数据
raf.seek(2*8);
raf.write("周期".getBytes());
raf.writeInt(103);
raf.close();
}
}
七、管道流
管道流:PipedInputStream、PipedOutputStream。1、特点:
1.1 将输入流和输出流连接,省去了用数组存储数据的中转环节。
1.2 使用多线程解决管道执行顺序问题,防止死锁情况。
2、连接方式:
2.1 connect(PipedOutputStream src):将PipedInputStream连接到PipedOutputStream。
2.2 PipedInputStream():创建尚未连接的PipedInputStream。
2.3 PipedOutputStream():创建尚未连接的PipedOutputStream。
- //管道流: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("读取前。。。未阻塞");
- 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 coming".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();
- }
- }
//管道流: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("读取前。。。未阻塞");
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 coming".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();
}
}
PS:集合中涉及到IO流的是Properies;IO中涉及到多线程的是管道流。
八、其他
1、操作基本数据类型:DataInputStream、DataOutputStream:用于操作基本数据类型的流对象。相关方法:
writeUTF(String str):以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。
意味着:只能通过对应的方法读取数据,用转换流读不出来。
readUTF(String str):专门用于读取UTF-8修改版编码。
PS:
UTF-8修改版占8个字节;UTF-8占6个字节;gbk占4个字节。假如用其他方法读取UTF-8修改版编码,
会出现EOFException异常,因为它需要读取8个字节才能结束,用其他方法读取会提前结束。
- //操作基本数据类型:DataInputStream、DataOutputStream
- 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("utf.txt"));
- String s = dis.readUTF();
- System.out.println(s);
- dis.close();
- }
- public static void writeUTFDemo() throws IOException
- {
- DataOutputStream dos = new DataOutputStream(new FileOutputStream("utf.txt"));
- 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(255);
- dos.writeBoolean(true);
- dos.writeDouble(9885.1516);
- dos.close();
- }
- }
//操作基本数据类型:DataInputStream、DataOutputStream
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("utf.txt"));
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void writeUTFDemo() throws IOException
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("utf.txt"));
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(255);
dos.writeBoolean(true);
dos.writeDouble(9885.1516);
dos.close();
}
}
2、操作字节数组ByteArrayInputStream:在构造时,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream:在构造时,不用定义数据目的。因为该对象中已经在内部封装了可变长度的字节数组,
也就是数据目的地。其缓冲区随着数据的不断写入而自动增长。
特点:这两个流对象都操作的是数组,没使用系统资源,不用进行close关闭。
优点:增加了对象的封装性;代码的复用性;用流的读写思想来操作数组,简化了书写。
流操作规律:
源设备:
键盘 System.in 硬盘 FileStream 内存 ArrayStream
目的设备:
控制台 System.out 硬盘 FileStream 内存 ArrayStream
- //操作字节数组:ByteArrayInputStream、ByteArrayOutputStream
- import java.io.*;
- class ByteArrayStream
- {
- public static void main(String[] args)
- {
- //数据源
- ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".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());
- //将此byte数组输出流的全部内容写入到指定的输出流参数中,会报出异常。
- //bos.writeTo(new FileOutputStream("a.txt"));
- }
- }
//操作字节数组:ByteArrayInputStream、ByteArrayOutputStream
import java.io.*;
class ByteArrayStream
{
public static void main(String[] args)
{
//数据源
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".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());
//将此byte数组输出流的全部内容写入到指定的输出流参数中,会报出异常。
//bos.writeTo(new FileOutputStream("a.txt"));
}
}
3、操作字符数组:CharArrayReader、CharArrayWrite4、操作字符串:StringReader、StringWriter
九、字符编码
1、编码表由来:计算机只能识别二进制数据,早期由来是电信号。为了方便用于计算机,让它可以识别各个国家的文字。
就将各个国家的文字用数字来表示,并一一对应,形成一张表--->编码表。
2、分类
ASCII:美国标准信息交换码:用一个字节的7位表示;
ISO8859-1:拉丁码表(欧洲码表):用一个字节的8位表示;
GB2312:中国的中文编码表;两个字节表示一个字符,两个字节的高位都是1,兼容和避免了跟ASCII码重复;
GBK:升级版的中文编码表,融合了更多的中文文字符号;有两万左右字符;
Unicode:国际标准码,融合入了多种文字。所有文字都用两个字节来表示,java语言使用的就是Unicode;
UTF-8:按字符大小分配存储空间,最多三个字节表示一个字符,并在首字母加入标识符,便于区分。
3、字符编码
3.1字符流的出现为了方便操作字符,更重要的是加入了编码转换。
编码转换通过子类转换流来完成:InputStreamReader、OutputStreamWriter。
在两个对象进行构造的时候可以加入字符集。
- //字符编码:编码转换:InputStreamReader、OutputStreamWriter
- import java.io.*;
- class EncodeStream
- {
- public static void main(String[] args) throws IOException
- {
- writeText();
- readText();
- }
- public static void readText() throws IOException
- {
- InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"UTF-8");
- char[] buf = new char[10];
- int len =isr.read(buf);
- String str = new String(buf,0,len);
- System.out.println(str);
- isr.close();
- }
- public static void writeText() throws IOException
- {
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");
- osw.write("你好");
- osw.close();
- }
- }
//字符编码:编码转换:InputStreamReader、OutputStreamWriter
import java.io.*;
class EncodeStream
{
public static void main(String[] args) throws IOException
{
writeText();
readText();
}
public static void readText() throws IOException
{
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"UTF-8");
char[] buf = new char[10];
int len =isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
public static void writeText() throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
}
3.2 编码:字符串变字节数组:String-->byte[];
byte[] getBytes(String charsetName):使用指定的字符集将此String解码为字节序列,并存储到数组中。
3.3 解码:
字节数组变字符串:byte[]-->String;
String(byte[],charsetName):将数组变成字符串。
- /*
- 编码:字符串变字节数组;解码:字节数组变字符串。
- 注意utf-8和GBK都识别中文的情况,因为都是别中文,它们之间解码会造成源码改变的情形。
- */
- import java.util.*;
- class EncodeDemo
- {
- public static void main(String[] args) throws Exception
- {
- String s = "你好";
- //编码
- byte[] b1 = s.getBytes("gbk");
- System.out.println(Arrays.toString(b1));
- //错误解码 因为ISO8859-1是拉丁码表,不包含中文码表,必然造成乱码。
- String s1 = new String(b1,"ISO8859-1");
- System.out.println("s1="+s1);
- //再编码 虽然s1是乱码,但也是一个字符对象,它的字节数组未变。
- //所以我们依旧可以通过字节数组获取正确的解码值。
- byte[] b2 = s1.getBytes("ISO8859-1");
- System.out.println(Arrays.toString(b2));
- //正确解码
- String s2 = new String(b2,"gbk");
- System.out.println("s2="+s2);
- }
- }
/*
编码:字符串变字节数组;解码:字节数组变字符串。
注意utf-8和GBK都识别中文的情况,因为都是别中文,它们之间解码会造成源码改变的情形。
*/
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
String s = "你好";
//编码
byte[] b1 = s.getBytes("gbk");
System.out.println(Arrays.toString(b1));
//错误解码 因为ISO8859-1是拉丁码表,不包含中文码表,必然造成乱码。
String s1 = new String(b1,"ISO8859-1");
System.out.println("s1="+s1);
//再编码 虽然s1是乱码,但也是一个字符对象,它的字节数组未变。
//所以我们依旧可以通过字节数组获取正确的解码值。
byte[] b2 = s1.getBytes("ISO8859-1");
System.out.println(Arrays.toString(b2));
//正确解码
String s2 = new String(b2,"gbk");
System.out.println("s2="+s2);
}
}
运行结果:
十、应用
- /*
- 有五个学生,每个学生有3门课的成绩。
- 从键盘输入以上数据(包括姓名,三门课成绩),
- 输入的格式:如:zhangsan,30,40,60计算出总成绩。
- 并把学生的信息和总分数从高到低存放在磁盘文件"stud.txt"中。
- 步骤:
- 1,描述学生对象。
- 2,定义一个可操作学生对象的工具类。
- 思路:
- 1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
- 2,学生有很多,那么就需要存储,使用到集合。要对学生的总分排序。可以使用TreeSet。
- 3,将集合的信息写入到一个文件中。
- */
- import java.io.*;
- import java.util.*;
- class Student implements Comparable<Student>
- {
- private String name;
- private int ma,cn,en;
- private int sum;
- Student(String name,int ma,int cn,int en)
- {
- this.name = name;
- this.ma = ma;
- this.cn = cn;
- this.en = en;
- sum = ma + cn + en;
- }
- //自然排序:返回负整数、零或正整数。根据此对象是小于、等于还是大于指定对象。
- public int compareTo(Student s)
- {
- int num = new Integer(this.sum).compareTo(new Integer(s.sum));
- if(sum==0)
- return this.name.compareTo(s.name);
- return num;
- }
- public String getName()
- {
- return name;
- }
- public int getSum()
- {
- return sum;
- }
- public int hashCode()
- {
- return name.hashCode()+sum*78;//保证值的唯一性。
- }
- //判断是否是同一个人。
- public boolean equals(Object obj)
- {
- if(!(obj instanceof Student))
- throw new ClassCastException("类型不匹配");
- Student s = (Student)obj;
- return this.name.equals(s.name) && this.sum==s.sum;
- }
- public String toString()
- {
- return "student["+name+","+ma+","+cn+","+en+"]";
- }
- }
- class StudentInfoTool
- {
- //默认比较方式
- public static Set<Student> getStudents() throws IOException
- {
- return getStudents(null);
- }
- //比较器
- public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException
- {
- BufferedReader bufr =
- new BufferedReader(new InputStreamReader(System.in));
- String line = null;
- Set<Student> stus = null;
- if(cmp==null)
- stus = new TreeSet<Student>();
- else
- stus = new TreeSet<Student>(cmp);
- while((line=bufr.readLine())!=null)
- {
- if("over".equals(line))
- break;
- String[] info = line.split(",");
- //解析一个字符串,并返回一个整数
- Student stu = new Student(info[0],Integer.parseInt(info[1]),
- Integer.parseInt(info[2]),
- Integer.parseInt(info[3]));
- stus.add(stu);
- }
- bufr.close();
- return stus;
- }
- public static void writeFile(Set<Student> stus) throws IOException
- {
- BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt"));
- for(Student stu : stus)
- {
- bufw.write(stu.toString() + "\t");
- bufw.write(stu.getSum() + "");
- bufw.newLine();
- bufw.flush();
- }
- bufw.close();
- }
- }
- class StudentInfoTest
- {
- public static void main(String[] args) throws IOException
- {
- //定义比较器,强行逆转
- Comparator<Student> cmp = Collections.reverseOrder();
- Set<Student> stus = StudentInfoTool.getStudents(cmp);
- StudentInfoTool.writeFile(stus);
- }
- }