Java -输入/输出-学习笔记
文章目录
(主要参考《疯狂Java》
1.File 类
File 类可以使用文件路径字符串来创建File实例,路径字符串既可以是绝对路径也可以是相对路径。
- 访问文件名相关方法:
- getName()
- getPath()
- getAbsoluteFile()
- getAbsolutPath()
- getParent()
- renameTo(File newName)
- 文件检测相关方法(返回boolean值)
- exists()
- canWrite()
- canRead()
- isFile()
- isDirectory()
- isAbsolute()
- 获取文件信息:
- lastModified()
- length()
- 文件操作相关方法
- createNewFile()
- delete()
- createTempFile(String prefix,String Suffix)
- createTempFile(String prefix,String Suffix,File directory)
- deleteOnExit()
- 目录操作相关方法
- mkdir()
- String[] list()
- file[] listFiles()
- static File[] listRoots()
import java.io.File;
public class file_test {
public static void main(String[] args){
var file=new File(".");
System.out.println(file.getName()+"---"+file.getPath()+"---"+file.getAbsolutePath()+"---"
+file.getAbsoluteFile()+"-----");
String[] list=file.list();
System.out.println("file_list:---");
for (var li:list)
System.out.println(li);
System.out.println("_________");
File[] filelist=file.listFiles();
for(var files:filelist){
System.out.println(files.getName());
if(files.isDirectory()){
for(var str:files.list((dir,name)->name.endsWith(".java")|| new File(name).isDirectory())){
System.out.println("-->"+str);
}
}
}
File[] f=File.listRoots();
for (var fs:f){
System.out.println("root: "+fs.getPath());
}
}
}
2.Java的IO流
在Java中把不同的输入输出源(键盘、文件、网络连接等)抽象地表述为“流”(Stream)。
分类:
-
输入流和输出流
-
字节流和字符流
-
节点流和处理流
Java的IO 流共涉及40多个类都是从如下4个抽象基类中派生出的:
- InputStream/Reader
- OutputStreamWrite
3. 字节流和字符流
3.1 InputStream和Reader
InputStream和Reader是所有输入流的抽象基类。
InputStream中包含三个方法:
- int read():从输入流中读取单个字节
- int read(byte[] b):从输入流中读取b.length个字节的数据并存储在数组b中
- int read(byte[] b ,int off, int len):从off位置开始读取len个数据到数组b
Reader中的三个方法:
- int read()
- int read(char[] cbuf)
- int read(char[] cbuf,int f,int len)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class file_test {
public static void main(String[] args) throws IOException {
var file=new File(".");
System.out.println(file.getName()+"---"+file.getPath()+"---"+file.getAbsolutePath()+"---"
+file.getAbsoluteFile()+"-----");
String[] list=file.list();
System.out.println("file_list:---");
System.out.println("_________");
File[] filelist=file.listFiles();
for(var files:filelist){
//System.out.println(files.getName());
if(files.isDirectory()){
for(var str:files.list((dir,name)->name.endsWith(".java")||
new File(name).isDirectory())){
//System.out.println("-->"+str);
if(str.equals("file_test.java"))
{
System.out.println("????");
String path= files+"\\"+str;
var ff=new File(path);
System.out.println(path+"--"+ff.isFile());
var filess=new FileInputStream(files+"\\"+str);
var bbuf= new byte[1024];
var hasread=0;
while ((hasread=filess.read(bbuf))>0){
System.out.println(new String(bbuf,0,hasread));
}
filess.close();
}
}
}
}
}
}
注意最后需要用close()来关闭文件输入流,或者也可以用try语句自动关闭。
3.2 outputStream和writer
import java.io.*;
public class write_test {
public static void main(String[] args){
try(
var fos=new FileWriter("test.txt");
) {fos.write("test");
for (int i=0;i<10;i++)
fos.write("row"+i+"\n");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 输入/输出流体系
使用PrintStream处理流来包装OutputStream,使用处理流后的输出流在输出时更加方便。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class print_test {
public static void main(String[] args){
try(
var fos=new FileOutputStream("test.txt");
var ps=new PrintStream(fos);
) {
ps.println("普通字符串");
ps.println(new print_test());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java的输入/输出流体系提供了近40个类。
5. 重定向标准输入/输出
三个方法:
- static void setErr(PrintStream err)
- static void setIn(InputStream in)
- static void setOut(PrintStream out)
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class redirectOUt {
public static void main(String[] args){
try(
var ps=new PrintStream(new FileOutputStream("test.txt"))
) {
System.setOut(ps);
System.out.println("test");
System.out.println(new redirectOUt());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
6. Java虚拟机读写其他进程数据
使用Runtime对象的exec()方法可以运行平台上的其他程序,该方法产生一个Process对象,代表由该Java程序启动的子进程。Process类提供了以下三个方法让程序和其子程序通信:
- InputStream getErrorStream():获取子程序的错误流
- InputStream getInputStream():~输入流
- OutputStream getOutputStream():~输出流
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class readprocess_test {
public static void main(String[] args) throws IOException {
Process p=Runtime.getRuntime().exec("javac");
try(
var br=new BufferedReader(new InputStreamReader(p.getInputStream()))
){
String Buff=null;
while((Buff=br.readLine())!=null){
System.out.println(Buff);
}
}
}
}
7. RandomAccessFile
RandomAccessFile可以自由访问文件的任意位置。创建其对象时需要指定一个mode参数,指定访问模式:
- “r”:只读
- “rw”:读写,若文件不存在则创建文件
- “rws”:读写,要求对文件的内容或元数据的每个更新都同步写入到底层存储设备
- “rwd”:读写,要求对文件的内容的每个更新都同步写入到底层存储设备
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class randomacess_test {
public static void main(String[] args){
try(
var raf=new RandomAccessFile("test.txt","rw")
){
System.out.println("The point is in"+raf.getFilePointer());
raf.seek(3);
raf.write("\nThe World ! \n".getBytes());
var bbf=new byte[1024];
var hasread=0;
raf.seek(0);
while ((hasread=raf.read(bbf))>0){
System.out.println(new String(bbf,0,hasread));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
8. 对象序列化
序列化机制允许将实现序列化的Java对象转换成字节序列,这些字节序列可以保存在磁盘上或通过网络传输,以备以后恢复成原来的对象。
比如我们新建一个普通的Java 类
public class serializable_test implements java.io.Serializable {
private String name;
private int age;
public serializable_test(String str,int age){
System.out.println("Flandre");
this.name=str;
this.age=age;
}
public void setname(String str){
this.name=str;
}
public void setage(int age){this.age=age;}
public String getName(){return this.name;}
public int getAge(){return this.age;}
}
然后将这个类的一个实例写入磁盘存储起来,然后读取出来
import java.io.*;
public class writeobject_test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
try(
var oos=new ObjectOutputStream(new FileOutputStream("object.txt"));
) {var per=new serializable_test("Flandre",495);
oos.writeObject(per);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
var ois=new ObjectInputStream(new FileInputStream("object.txt"));
var p=(serializable_test)ois.readObject();
System.out.println(p.getName()+"--"+p.getAge());
}
}
9. NIO (New IO)
Java中与新IO相关的包如下:
- java.nio
- java.nio.channels
- java.nio.charset
- java.nio.channels.spi
- java.nio.charset.spi
9.1 Buffer
Buffer是一个抽象类,最常用的子类是ByteBuffer,可以在底层字节数组上进行get/set操作。此外其他数据类型(除boolean外)都有相应的Buffer类:CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。
Buffer中由三个重要的概念:
- capacity:缓冲区容量
- limit:limit之后的数据不可被读写
- position:指明下一个可以被读写的缓冲区位置索引
import java.nio.CharBuffer;
public class buffer_test {
public static void main(String[] args){
CharBuffer cb=CharBuffer.allocate(8);
System.out.println(cb.capacity()+"---"+cb.limit()+"---"+cb.position());
cb.put('a');
cb.put('b');
cb.put('c');
System.out.println("position "+cb.position());
cb.flip();
System.out.println(cb.limit());
System.out.println(cb.position());
cb.clear();
System.out.println(cb.capacity()+"---"+cb.limit()+"---"+cb.position());
System.out.println(cb.get(2));
System.out.println(cb.capacity()+"---"+cb.limit()+"---"+cb.position());
}
}
9.2 Channer
Channer可以直接将文件的部分或全部映射成Buffer。但程序不能直接访问Channel中的数据,包括读写,只能与Buffer进行交互。
import java.io.*;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
public class channel_test {
public static void main(String[] args){
File f=new File("test.txt");
try(
var chan=new FileInputStream(f).getChannel();
var oc=new FileOutputStream("txt.txt").getChannel();
) {
MappedByteBuffer bf=chan.map(FileChannel.MapMode.READ_ONLY,0,f.length());
Charset c= Charset.forName("GBK");
oc.write(bf);
bf.clear();
CharsetDecoder dec=c.newDecoder();
CharBuffer charBuffer=dec.decode(bf);
System.out.println(charBuffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
9.3 字符集和Charset
我们知道,所有文件在底层都是二进制文件,即字节码。对于文本文件,我们能看到一个个字符是因为系统将底层的二进制文件序列转换成字符,其中涉及两个概念:Encode9(编码)、Decode(解码)。
Java默认使用Unicode字符集。可以用Charset来处理字节序列和字符序列(字符串)之间的转换关系。
Charset提供一个availableCharsets()静态方法来获取当前JDK所支持的所有字符集。如下:
import javax.print.DocFlavor;
import java.nio.charset.Charset;
import java.util.SortedMap;
public class charset_test {
public static void main(String[] args){
SortedMap<String, Charset> map= Charset.availableCharsets();
for (var c:map.keySet()){
System.out.println(c+"-->"+map.get(c));
}
}
}
以下几个字符串别名是常见的:
- GBK:简体中文字符集
- BIG5:繁体中文字符集
- ISO-8859-1:ISO拉丁字母表No.1,也叫做ISO-LATIM-1
- UTF-8:8位UCS转换格式
- UTF-16BE:16位UCS转换格式,Big-endian字节顺序
- UTF-16LE:16位UCS转换格式,Little-endian字节顺序
- UTF-16:16位UCS转换格式,字节顺序由可选的字节顺序标记来标识
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class Charsets {
public static void main(String[] args) throws CharacterCodingException {
Charset charset=Charset.forName("GBK");
CharsetDecoder charsetDecoder=charset.newDecoder();
CharsetEncoder charsetEncoder=charset.newEncoder();
CharBuffer charBuffer=CharBuffer.allocate(8);
charBuffer.put('博');
charBuffer.put('丽');
charBuffer.put('灵');
charBuffer.put('梦');
charBuffer.flip();
ByteBuffer byteBuffer=charsetEncoder.encode(charBuffer);
for(var i=0;i<byteBuffer.capacity();i++){
System.out.println(byteBuffer.get(i)+" ");
}
System.out.println("\n"+charsetDecoder.decode(byteBuffer));
}
}
9.4 文件锁
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;
public class lock_test {
public static void main(String[] args){
try(
var channel=new FileOutputStream("test.txt").getChannel();
) {
FileLock lock=channel.tryLock();
Thread.sleep(10000);
lock.release();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
10. NIO.2的功能和用法
10.1 Path、Paths和Files核心API
import java.awt.*;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class path_test {
public static void main(String[]args) throws IOException {
Path path = Paths.get(".");
System.out.println("Path中包含的路径数量: "+path.getNameCount());
System.out.println(path.getRoot());
Path abs=path.toAbsolutePath();
System.out.println(abs);
System.out.println(abs.getRoot()+"----"+abs.getNameCount()+"----"+abs.getName(3));
Path path1= Paths.get("E:","publish","codes");
System.out.println(path1);
Files.copy(Paths.get("test.txt"),new FileOutputStream("a.txt"));
System.out.println(Files.isHidden(Paths.get("test.txt")));
List<String> poem=new ArrayList<>();
poem.add("aaa");
poem.add("bbb");
Files.write(Paths.get("poem.txt"),poem, Charset.forName("gbk"));
System.out.println("-----");
Files.list(Paths.get(".")).forEach(paths->System.out.println(paths));
Files.lines(Paths.get("test.txt"),Charset.forName("gbk")).forEach(e->System.out.println(e));
FileStore sc=Files.getFileStore(Paths.get("D:"));
System.out.println(sc.getTotalSpace()+"---"+sc.getUsableSpace());
}
}
10.2 用FileVisitor遍历文件和目录
Files类提供以下两种方法来遍历文件和子目录
- walkFileTree(Path start,FileVisitor<? super Path>visitor)
- walkFileTree(Path start,Set options,int maxDepth,FileVisitor<? super Path>visit)
其中都需要FileVisitor参数,遍历文件和子目录都会触发FileVisitor中的相应方法:
- FileVisitResult postVisitDirectory(T dir,IOException exc)
- FileVisitResult priVisitDirectory(T dir,BasicFileAttributes attrs)
- FileVisitResult visitFile(T file,IOException exec)
- FileVisitResult visitFileFailed(T file,IOException exec)
FileVisitResult为一个枚举类,代表访问之后的后续行为,由以下几种后续行为:
- CONTINUE
- SKIP_SIBLINGS
- SKIP_SUBTREE
- TERMINATE
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class filevisit_test {
public static void main(String[] args) throws IOException {
Files.walkFileTree(Paths.get("C:"),new SimpleFileVisitor<Path>(){
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)throws IOException{
System.out.println("正在访问"+file+"文件");
if (file.endsWith(".java")){
System.out.println("ok");
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,BasicFileAttributes attrs)throws IOException{
System.out.println("正在访问->"+dir+"路径");
return FileVisitResult.CONTINUE;
}
});
}
}
10.3 用WatchService监控文件变化
import java.io.IOException;
import java.nio.file.*;
public class watch_test {
public static void main(String[] args) throws IOException, InterruptedException {
WatchService watchService= FileSystems.getDefault().newWatchService();
Paths.get(".").register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE);
while(true){
WatchKey key=watchService.take();
for(WatchEvent<?> event:key.pollEvents()){
System.out.println(event.context()+"文件发生了"+event.kind()+"事件!");
}
boolean valid=key.reset();
if(!valid){
break;
}
}
}
}
10.4 访问文件属性
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Date;
import java.util.List;
public class attribute_test {
public static void main(String[] args) throws IOException {
Path testpath= Paths.get("test.txt");
BasicFileAttributeView basicFileAttributeView= Files.getFileAttributeView(testpath,
BasicFileAttributeView.class);
BasicFileAttributes basicFileAttributes=basicFileAttributeView.readAttributes();
System.out.println("ceate time:"+new Date(basicFileAttributes.creationTime().toMillis()));
System.out.println(new Date(basicFileAttributes.lastAccessTime().toMillis()));
System.out.println(new Date(basicFileAttributes.lastModifiedTime().toMillis()));
System.out.println(basicFileAttributes.size());
FileOwnerAttributeView fileOwnerAttributeView=Files.getFileAttributeView(testpath,
FileOwnerAttributeView.class);
System.out.println(fileOwnerAttributeView.getOwner());
UserPrincipal userPrincipal= FileSystems.getDefault().getUserPrincipalLookupService().
lookupPrincipalByName("guest");
fileOwnerAttributeView.setOwner(userPrincipal);
UserDefinedFileAttributeView userDefinedFileAttributeView=Files.getFileAttributeView(
testpath,UserDefinedFileAttributeView.class
);
List<String> atrr=userDefinedFileAttributeView.list();
for(var name:atrr){
ByteBuffer buffer=ByteBuffer.allocate(userDefinedFileAttributeView.size(name));
userDefinedFileAttributeView.read(name,buffer);
buffer.flip();
String value= Charset.defaultCharset().decode(buffer).toString();
System.out.println(name+"---->"+value);
}
userDefinedFileAttributeView.write("发行者",Charset.defaultCharset().encode("xhh"));
DosFileAttributeView dosFileAttributeView=Files.getFileAttributeView(testpath,
DosFileAttributeView.class);
dosFileAttributeView.setHidden(true);
dosFileAttributeView.setReadOnly(true);
}
}