转载

输入与输出处理

输入/输出流

读取字节的源头被称为输入流,字节的目的地被称为输出流。

获取流对象

//从文件获取流
InputStream in = Files.newInputStream(path);  
OutputStream out = Files.newOutputStream(path);

//如果对象是网页
URL url = new URL("https://www.baidu.com/");
InputStream in = url.openStream(); 

//从一个字节数组读取数据
byte[] bytes = ...
InputStream in = new ByteArrayInputStream(bytes);

字符编码

输入和输出流按顺序读/写字节,文本是要按字符读/写,常用的字符编码是UTF-8或GBK。

一些方法允许通过Charset对象或一个字符串指定字符编码,建议使用StandardCharsets常量。

文本输入

对于较短的文本文件,可以将文件读取到一个字符串

String content = new String(Files.readAllBytes(path), "GBK");

按行读取文件:

List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);

按流处理:

try(Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)){  
  
}catch (Exception ex){  
  
}

如果输入源并非来自文件:

URL url = new URL("https://www.bilibili.com/");  
try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()))){  
    Stream<String> lines = bufferedReader.lines();  
  
}

文本输出

try(PrintWriter out = new PrintWriter(Files.newBufferedWriter(path, StandardCharsets.UTF_8))){  
    out.write("开始写入...");  
    out.flush();  
}  
catch (Exception ex)  {  
  
}

如果你已经有一个变量包含了要写的文本:

String content = "内容1";  
 Files.write(path, content.getBytes(StandardCharsets.UTF_8));  
 //或者  
 List<String> lines = new ArrayList<>();  
 Files.write(path, lines, StandardCharsets.UTF_8);

向文件追加内容:

Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);  
//或者  
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.APPEND);

文件锁

当多个同时执行的程序对同一个文件进行修改时,它们需要协调;否则,文件很容易被损坏。使用文件锁机制可以解决这类问题。

例如一个简单例子:

FileChannel channel = FileChannel.open(path);  
try(FileLock lock = channel.lock()){  
  
}catch (Exception ex){  
  
}

路径、文件和目录

路径

从根路径开始的路径被称为绝对路径,否则就是相对路径。

例子:

//绝对路径
 Path path = Paths.get("C://Users//HP//Desktop//新建文本文档.txt");  
 
//或者
 Path path = Paths.get("C://","Users","HP","Desktop","新建文本文档.txt");
 
 //相对路径,路径为文件在工程中的相对路径
 Path path = Paths.get("src","in.txt");
 
 //对路径进行组合,调用p.resolve(q)会根据这些规则返回一个路径对象.如果q是绝对路径,则返回结果就是q,否则,返回结果就是先p然后q。
 //假设你的程序需要在主目录的相对路径下找配置文件:
 Path path = homeDirectory.resolve("myapp/work");

创建文件和目录

//创建一个空文件  
Path path = Paths.get("src","in.txt");  
if(!Files.exists(path)){  
    Files.createFile(path);  
}

//创建一个空目录
Path path = Paths.get("src","in");  
if(!Files.exists(path)){  
    Files.createDirectory(path);  
}

复制、移动和删除文件

如果移动或复制的目标已经存在,则必须指定StandardCopyOption的字段,否则会失败。

//移动,ATOMIC_MOVE选项指定移动应该是原子操作,这样才能确保移动保存成功完成,或继续保留在当前位置
Path fromPath = Paths.get("src","in.txt");  
Path toPatch = Paths.get("src","in","in.txt");  
Files.move(fromPath, toPatch, StandardCopyOption.ATOMIC_MOVE);

//复制,COPY_ATTRIBUTES选项能覆盖已经存在的目标文件或目录
Files.copy(fromPath, toPatch, StandardCopyOption.COPY_ATTRIBUTES);

删除一个文件

boolean deleted = Files.deleteIfExists(path);

HTTP连接

URL类能提供的控制有限,如果想写数据,或获取web资源的额外信息可以使用

--add-modules jdk.incubator.httpclient

序列化

对象的序列化是一种将一个对象转化成 字节 方便传送到别处或储存在硬盘上,并且能再从转化成的字节重构对象的机制。

Serializable接口

为了一个对象能被序列化,即把它转化成一段字节,它必须是一个实现了Serializable接口的类的实例。这是一个没有方法的标记接口。

例子:

//所有实例的变量都是基本类型或枚举类型,或者引用其他可序列化对象
class Employee implements Serializable{  
    private String name;  
    private double salary;  
    public Employee(String name, double salary)  
    {  
        this.setName(name);  
        this.setSalary(salary);  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public double getSalary() {  
        return salary;  
    }  
  
    public void setSalary(double salary) {  
        this.salary = salary;  
    }  
}

要序列化对象,你需要一个从接收实际字节的OutputStream构造的ObjectOutputStream对象。

Path path = Paths.get("C://","Users","HP","Desktop","新建文本文档.txt");  
try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(path))){  
    Employee peter = new Employee("Peter", 90000);  
    Employee paul = new Employee("paul", 190000);  
    //写入对象  
    out.writeObject(peter);  
    out.writeObject(paul);  
  
}catch (Exception ex){  
  
}  
//读回对象  
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(path))){  
 
  //然后按照写入的顺序用readObject方法读取对象  
  Employee e1 = (Employee)in.readObject();  
  Employee e2 = (Employee)in.readObject();  
}  
catch (Exception ex){  
}

瞬态实例变量

为了实现某些实例变量不被序列化,简单的方法就是给这个变量打一个transient修饰符标记。

private transient double salary;
原文  https://segmentfault.com/a/1190000021509626
正文到此结束
Loading...