17 IO
关于IO流,可参见: Java IO流学习总结
17.1 IO流
IO流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式。
- 流按操作数据分为两种:字节流和字符流;
- 按流向分为:输入流,输出流。
字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。再对这个文字进行操作。简单说:字节流+编码表。
17.1.1 IO流常用基类
字节流的抽象基类:InputStream,OutputStream.
字符流的抽象基类:Reader,Writer.
P.S.
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
写
- 需求:将一些文字存储到硬盘一个文件中。
- 记住:如果要操作文字数据,建议优先考虑字符流。
而且要将数据从内存写到硬盘上,要使用字符流中的输出流:Writer。
硬盘的数据基本体现是文件,希望找到一个可以操作文件的Writer:FileWriter。
例1:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
FileWriter fw = new FileWriter("F:\\javatest\\IOtest\\demo.txt");
fw.write("Gabriel1");
//刷新流对象中缓冲的数据,将数据刷至目的地中
fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部缓冲的数据,将数据刷到目的地中,
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会关闭流
fw.close();
}
}
例2:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw =new FileWriter("F:\\javatest\\IOtest\\demo.txt");
fw.write("abc");
} catch (IOException e) {
System.out.println("catch:"+e.toString());
e.printStackTrace();
}finally{
try {
if(fw!=null)
fw.close();
} catch (IOException e) {
System.out.println("catch:"+e.toString());
}
}
}
}
将abc写入到demo.txt中。
例3:
public class FileWriterDemo {
public static void main(String[] args) {
try {
FileWriter fw = new FileWriter("F:\\javatest\\IOtest\\demo.txt",true);
fw.write("a");
fw.close();
} catch (IOException e) {
System.out.println("catch:"+e.toString());
e.printStackTrace();
}
}
}
将a写入到demo.txt中,并接着文字往后写,为“abca”。
读
- 方式1:
第一种读取方式:使用read()方法读取文本文件数据。
例4:
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("F:\\javatest\\IOtest\\demo.txt");
//调用读取流对象的read方法,一次读一个字符,每次调用自动往下读
while(true){
int ch = fr.read();
if(ch==-1)
break;
System.out.println("ch:"+(char)ch);
}
fr.close();
}
}
运行结果:
- 方式2:
第二种读取方式:使用read(char[])方法读取文本文件数据。
例5:
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
char[] buf = new char[2];
FileReader fr = new FileReader("F:\\javatest\\IOtest\\demo.txt");
int num = 0;
while((num=fr.read(buf))!=-1){
System.out.println("num:"+num+".."+new String(buf,0,num));
}
fr.close();
}
}
运行结果:
拷贝
- 在D盘创建一个文件,用于存储C盘文件中的数据;
- 定义读取流和C盘文件关联;
- 通过不断的读写完成数据存储;
- 关闭资源。
方法一:
例6:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopeTest {
public static void main(String[] args) throws IOException {
copy_1();
}
public static void copy_1() throws IOException{
FileWriter fw = new FileWriter("D:\\RuntimeDemo_copy.txt");
FileReader fr = new FileReader("F:\\javatest\\Circle.java");
int ch = 0;
while((ch=fr.read())!=-1){
fw.write(ch);
}
fw.close();
fr.close();
}
}
方法二:
例7:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopeTest {
public static void main(String[] args) throws IOException {
copy_1();
}
public static void copy_1() throws IOException{
FileWriter fw = null;
FileReader fr = null;
fw = new FileWriter("D:\\RuntimeDemo_copy.txt");
fr = new FileReader("F:\\javatest\\BasicGeneric.java");
char[] ch = new char[1024];
int len = 0;
while((len=fr.read(ch))!=-1){
fw.write(ch,0,len);
}
fw.close();
fr.close();
}
}
缓冲区
缓冲区的出现提高了对数据的读写效率。
对应类:
- BufferedWriter
- BufferedReader
P.S.
缓冲区要结合流才可以使用。
作用:在流的基础上对流的功能进行了增强。
例8:
import java.io.*;
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("F:\\javatest\\BasicGeneric.java");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null){
System.out.println(line);
}
bufr.close();
}
}
例9:
import java.io.*;
public class CopeMp {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
public static void copy_1() throws IOException{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("C:/Users/Administrator/Desktop/[解读中国经济].林毅夫.扫描版(ED2000.COM).pdf"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("D:\\Demo_copy.pdf"));
int by = 0;
while((by=bufis.read())!=-1){
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
例10:
import java.io.IOException;
import java.io.InputStream;
public class ReadInTest {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true){
int ch = in.read();
if(ch=='\r'){
continue;
}
if(ch=='\n'){
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0, sb.length());
}
else
sb.append((char)ch);
}
}
}
运行结果:将输入的字符串转成大写输出
File类
创建
- boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false;和输出流不一样,输出流对象一建立即创建文件,而且文件已经存在,会覆盖;
- boolean mkdir():创建文件夹;
- boolean mkdirs():创建多级文件夹。
删除
- boolean delete():删除失败返回false;
- void deleteOnExit():在程序退出时删除指定文件。
- 判断
- boolean exists():文件是否存在。
- isFile();
- isDirectory();
- isHidden();
- isAbsolute()
- 获取
- getName();
- getPath();
- getParent();
- getAbsolutePath();
- lastModified();
- length();
例11:
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
method();
method_1();
method_2();
method_3();
}
public static void method() throws IOException{
File f = new File("a.txt");
write("create:"+f.createNewFile());
//write("delete:"+f.delete());
}
public static void method_1(){
File f = new File("FileDemo.java");
f.mkdir();
write("execute:"+f.canExecute());
}
public static void method_2(){
File f = new File("file.java");
//f.mkdir();
//判断文件对象是否是文件或者目的时,
//必须要先判断该文件对象封装的内容是否存在。
write(f.exists());
write("execute:"+f.isDirectory());
write("execute:"+f.isFile());
write(f.isAbsolute());
}
public static void method_3(){
File f = new File("b.java");
write("path:"+f.getPath());
write("absolutepath"+f.getAbsolutePath());
write("parent:"+f.getParent());//该方法绝对路径中的父目录,获得相对路径则返回null
}
public static void write(Object obj){
System.out.println(obj);
}
}
第二次运行结果:
例12:
import java.io.File;
import java.io.FilenameFilter;
public class FielDemo2 {
public static void main(String[] args) {
listRootsDemo();
listDemo();
File f = new File("E:/IELTS");
show(f,0);
}
public static void listDemo(){
File f = new File("d:\\software");
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);
}
}
public static void show(File dir,int level){
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for(int x=0;x<files.length;x++){
if(files[x].isDirectory()){
show(files[x],level);//递归法
}
if(files[x].isFile())
System.out.println(getLevel(level)+files[x]);
}
}
public static String getLevel(int level){
StringBuilder sb = new StringBuilder();
sb.append("|--");
for(int i=0;i<level;i++){
sb.insert(0, " ");
}
return sb.toString();
}
}
运行结果:
例13(查询文件数量):
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CreatFileList {
public static void main(String[] args) throws IOException {
File dir = new File("F:/javatest");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
File file = new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File> list){
File[] files = dir.listFiles();
for(File file:files){
if(file.isDirectory())
{
fileToList(file,list);
}
if(file.getName().endsWith(".java"))
list.add(file);
}
}
public static void writeToFile(List<File> list,String javaListFile) throws IOException{
BufferedWriter bufw = null;
try {
bufw = new BufferedWriter(new FileWriter(javaListFile));
for(File f:list){
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(bufw!=null){
bufw.close();
}
}
}
}
运行结果:将F:/javatest目录下所有的.java文件的地址打印到F:/javatest/javalist.txt中。
Properties集合
Map
- |–Hashtable
- |–Properties
特点:
- 该集合中的键和值都是字符串类型。
- 集合中的数据可以保存到流中,或者从流中获取。
- 通常该集合用于操作以键值对形式存在的配置文件。
Properties集合的存和取。
例14:
import java.io.*;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
setAndGet();
method_1();
}
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){
if(line.startsWith("#"))
continue;
String[] arr = line.split("=");
prop.setProperty(arr[0], arr[1]);
}
bufr.close();
System.out.println(prop);
}
public static void setAndGet() throws IOException{
Properties prop = new Properties();
prop.setProperty("Gabriel","20");
prop.setProperty("Mary","12");
prop.setProperty("Lucy","11");
prop.setProperty("Gabriel", "5");
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos, "name+age");
fos.close();
Set<String> names = prop.stringPropertyNames();
for(String name:names){
String value = prop.getProperty(name);
System.out.println(name+" "+value);
}
}
}
运行结果:
例15:
计数器:获取一个应用程序的运行次数,超过5次则提醒已使用超限。
import java.io.*;
import java.util.Properties;
public 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, "count");
fos.close();
fis.close();
}
}
打印流
PrintWriter与PrintStream:可以直接操作输入流和文件。
- PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
- 与其他输出流不同,PrintStream永远不会抛出IOException。
- PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。
- 在需要写入字符而不是写入字节的情况下,应该使用PrintWriter类。
PrintStream:
- 提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式
- 它不抛IOException
构造函数,接收三种类型的值:
- 字符串路径
- File对象
- 字节输出流
PrintWriter:字符打印流
构造函数参数:
- 字符串路径
- File对象
- 字节输出流
- 字符输出流
例16:
import java.io.*;
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line)){
break;
}
out.println(line.toUpperCase());
}
out.close();
bufr.close();
}
}
序列流
SequenceInputStream:对多个流进行合并。
例17:
import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
public class SequenceDemo {
public static void main(String[] args) throws IOException {
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("F:\\JavaProject\\TestIO\\1.txt"));
v.add(new FileInputStream("F:\\JavaProject\\TestIO\\2.txt"));
v.add(new FileInputStream("F:\\JavaProject\\TestIO\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("F:\\JavaProject\\TestIO\\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();
}
}
例18:合并与分割文件:
import java.io.*;
import java.util.*;
public class SplitFile {
public static void main(String[] args) throws IOException {
splitFile();
merge();
}
public static void merge() throws IOException{//合并文件
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
//将碎片文件和流对象添加并存储在集合中
for(int x=1;x<=3;x++){
al.add(new FileInputStream("F:\\JavaProject\\TestIO\\"+x+".part"));
}
final Iterator<FileInputStream> it = al.iterator();
//多个流合并为序列流
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
public boolean hasMoreElements(){
return it.hasNext();
}
public FileInputStream nextElement() {
return it.next();
}
};//匿名类
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("F:\\JavaProject\\TestIO\\0.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
public static void splitFile() throws IOException{ //分割文件
FileInputStream fis = new FileInputStream("F:\\JavaProject\\TestIO\\1.jpg");
FileOutputStream fos = null;
byte[] buf = new byte[1024*20];
int len = 0;
int count = 1;
while((len=fis.read(buf))!=-1){
fos = new FileOutputStream("F:\\JavaProject\\TestIO\\"+(count++)+".part");
fos.write(buf, 0, len);
fos.close();
}
fis.close();
}
}
管道流
PipedInputStream和PipedOutputStream:输入输出可以直接进行连接,通过结合线程使用。
例19:
import java.io.*;
public 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();
}
}
class Read implements Runnable{
private PipedInputStream in;
Read(PipedInputStream in){
this.in = in;
}
public void run() {
try {
byte[] buf = new byte[1024];
int len = in.read(buf);
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 {
Thread.sleep(2000);
out.write("piped".getBytes());
out.close();
} catch (Exception e) {
throw new RuntimeException("管道输出流失败");
}
}
}
运行结果:piped