## File
java.io.File
### 构造方法:
new File(String 路径)
new File(String 父目录,String 文件名)
new File(File 父目录对象,String 文件名)
```java
*: 路径分界符 File.separator
*: 绝对路径 和 相对路径
绝对路径:从盘符或者根目录出发定位我们要的文件 一定以/或者x:开头
相对路径:从程序认定的主目录出发定位我们的文件
```
### 特等优先级方法:3个
```java
static listRoots() : 列出当前计算机的所有"根目录"
String[] list() : 列出一个目录当中所有的"文件名字"
File[] listFiles() : 列出一个目录当中所有的"文件对象" "*****"
```
### 一等优先级方法: 12个
四个只读操作: exists() isFile() isDirectory() length()
三个高危写操作: delete() mkdirs() **renameTo()**
三个得到系列: getName() getParent() getAbsolutePath()
两个时间相关: setLastModified() **lastModified()**
```java
/**
* 请将D:\测试\a.txt文件的最后一次修改时间 改为 当前修改时间的一天前
* File lastModified() setLastModified()
* 时间戳就是从1970-01-01开始所经过的毫秒数,什么时候获取时间戳,就是到那个时间点所经历的毫秒数
*/
public class FileTest7 {
public static void main(String[] args) {
File file = new File("D:\\测试\\a.txt");
long lastModified = file.lastModified();
long day = 24L*60*60*1000; //一天所经过的毫秒数
file.setLastModified(lastModified-day);
}
}
```
## 时间戳如何解析:
```java
1st java.util.Date
构造方法传参可以指定要表达的时间
getYear() getMonth() getDate()
getHours() getMinutes() getSeconds()
2nd java.util.Calendar
如何得到实例:不能new 只能Calendar.getInstance();
调整时间:setTimeInMillis(时间戳);
得到数据:get(x) 获取的是该对象创建时的时间,是静态的不随时间变化而变化。
x: 1 2+1 5 11 12 13 7-1
3rd java.text.SimpleDateFormat
构造方法要求指定日期格式:yyyy-MM-dd HH:mm:ss
如果已经有时间戳 想要 字符串: format()
如果已经有字符串 想要 时间戳: parse() + getTime()
```
## 递归遍历攻略帖
01.我们需要一个能够过滤所有子目录的过滤器 - 最好使用单例 [醉汉式]
FileFilter public boolean accept(File file){}
02.我们需要一个能够过滤所有目标文件的过滤器 - 最好使用单例 [懒汉式]
03.这里才是真正的核心 那个递归调用的方法
方法的参数 代表当前正要对付的那个目录
```c++
3-1: 利用1st开发完成的过滤器 过滤目标目录当中所有的子目录
3-2: 利用2nd开发完成的过滤器 过滤目标目录中所有目标文件
3-3: 判断3-1或者3-2得到的是不是为空 防止没有权限导致空指针异常
3-4: 遍历每个3-1得到的子目录 再次调用03方法
3-5: 遍历3-2得到的每个目标文件 进行对应的操作
```
04.主方法当中利用listRoots()得到当前计算机的所有根目录
遍历每个根目录 依次调用03那个方法
```java
/**
* 1)递归遍历文件
* 2)将文件放到集合中
* 3)按照文件名从长到短对集合进行排序
*/
public class FileFilterTest2 {
private static List aList = new ArrayList<String>();
public static void main(String[] args) {
File dir = new File("D:\\jdk-src");
File[] files = dir.listFiles();
for (File file : files) {
kiss(file);
}
System.out.println("文件名最长的为:"+aList.get(0));
System.out.println("src文件夹文件个数为:"+aList.size());
}
//递归遍历
public static void kiss(File tar) {
File[] f1 = tar.listFiles((x) -> x.isDirectory());
File[] f2 = tar.listFiles((x) -> x.isFile());
if (f1 == null || f2 == null) return;
for (File file : f1) {
kiss(file);
}
for (File file : f2) {
aList.add(file.getName());
}
Collections.sort(aList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
});
}
}
```
# day02
## 字节IO流
IO流 I=Input=输入 O=Output=输出
流:数据从源点传输到汇点的管道
流的分类:
按照方向分: 输入流 / 输出流 参照物:当前程序
按照单位分: 字节流 / 字符流
按照功能分: 节点流 / 过滤流(包装流、处理流)
让我们一起上路:
InputStream 所有字节输入流统一的父类 抽象类
int read()
int read(byte[] data) *****
int read(byte[] data,int off,int len)
OutputStream 所有字节输出流统一的父类 抽象类
write(int data)
write(byte[] data)
write(byte[] data,int off,int len) *****
FileInputStream 输入流 字节流 节点流
FileOutputStream 输出流 字节流 节点流
*: 它们都是节点流 构造方法允许传入String路径或者File对象
*: 它们都是节点流 但是只能连接文件 不能连接目录
否则直接出现异常 FileNotFoundException
***: FileInputStream 最常用的是read(byte[] data)**
***: FileOutputStream 最常用的却是write(byte[],int,int)**
*: FileInputStream 以-1作为读取结束的标识
*: FileOutputStream 是节点输出流
**节点输出流创建对象的时候 如果其连接的文件不存在**
**也会在创建流的第一时间 自动创建 不用手建**
其实File类当中有个方法createNewFile() 咱没讲!
但是 如果其连接的目录结构都不存在
不但不给创建 还会出现异常
所以File类当中有个方法**mkdirs**() 一等优先级!
*: FileOutputStream 是节点输出流
**节点输出流是非常可怕的 它极具杀伤力**
**如果其创建对象的时候 连接的文件已经存在**
**也会在创建流的那一刻** **被新的空白文件直接替换**
**如果我们的需求是不想替换**
**只想在原有内容的最后** **继续追加新内容**
**可以构造方法传参 指定追加模式开启**
**new FileOutputStream("focus.txt",true);**
*: 用完流的第一时间 请及时关闭流 以解除文件的占用状态
BufferedInputStream 输入流 字节流 过滤流
BufferedOutputStream 输出流 字节流 过滤流
*: **作为过滤流的它们 是为了给原本的流添加缓冲空间**
**从而提高每次读写的吞吐量** **进而提高效率**
*: **作为过滤流的它们** **不能直接连接文件** **只能连接其它的流**
*: **BufferedInputStream** **最常用的** read() 读取一个字节
***: BufferedOutputStream 最常用的write(int data) 写出一个字节**
*: BufferedInputStream 以-1作为读取结束的标识
*: BufferedOutputStream 是带缓冲的输出流
使用带缓冲的输出流 务必注意及时清空缓冲
以防止数据滞留缓冲区 导致丢失!
缓冲区什么条件下会清空:
**1.满了自动清空 无需操作**
**2.关闭流的操作 会触发清空缓冲**
**3.主动清空缓冲 flush();**
DataInputStream 输入流 字节流 过滤流
DataOutputStream 输出流 字节流 过滤流
*: 它们给原本的流添加读写基本数据类型的功能
*: 作为过滤流的它们 不能直接连接文件 只能连接其它的流
```Java
boolean char byte short int long float double
*: DataInputStream 提供的核心方法 readXxxx() 有返回值
*: DataOutputStream 提供的核心方法 writeXxxx() 要参数
*: DataInputStream 不能再以-1作为读取结束的标识了
如果一旦到达文件结尾 还继续尝试读取
将会直接触发EOFException => End Of File
```
## 字节IO小总结
InputStream 所有字节输入流统一的父类 抽象类
OutputStream 所有字节输出流统一的父类 抽象类
FileInputStream 节点流
FileOutputStream 节点流 *****
**节点输出流创建对象的时候 连接的文件如果不存在 它能自己建**
**如果已经存在 它还建 它用新的覆盖你的老文件!!!**
BufferedInputStream 过滤流==包装流==处理流
BufferedOutputStream 过滤流==包装流==处理流
它们给原本的流添加缓冲空间 从而提高每次读写的吞吐量
进而减少了往返的次数 从而提高了效率
*:**BufferedOutputStream 带缓冲的输出流 务必注意清空缓冲**
DataInputStream 过滤流==包装流==处理流
DataOutputStream 过滤流==包装流==处理流
它们给原本的流添加读写基本数据类型的功能
DataInputStream => readXxx()
DataOutputStream => writeXxxx()
## 学好IO流必须要会做的8大需求
```java
1> 使用标准的节点流 配合一个自定义的大数组 完成文件复制 [*]
FileInputStream + FileOutputStream
*: 标准TWR *: 连环try
2> 使用带缓冲的过滤流 一次一个字节的完成文件复制
BufferedInputStream + BufferedOutputStream
*: 标准TWR *: 连环try
3> 将内存当中一个基本数据类型变量 保存到磁盘中去
DataOutputStream writeXxxx()
*: 标准TWR *: 连环try
4> 从文件当中读取一个基本数据类型变量 到程序当中
DataInputStream readXxxx();
*: 标准TWR *: 连环try
5> 将内存当中一个引用类型的对象 保存到磁盘中去
ObjectOutputStream writeObject();
*: 标准TWR *: 连环try
6> 从文件当中读取一个引用类型的对象 到程序当中
ObjectInputStream readObject()
*: 标准TWR *: 连环try
7> 以一行为单位的写出文本文件 [*****]
PrintWriter println()
*: 标准TWR *: 连环try
8> 以一行为单位读取文本文件 [*****]
BufferedReader readLine() null
```
# day03 对象流+字符流
基本数据类型 如何保存到文件当中 如何读取到程序当中
引用数据类型 如何保存到文件当中 如何读取到程序当中
DataInputStream 读取基本数据类型的功能
DataOutputStream 写出基本数据类型的功能
ObjectInputStream 读取引用数据类型的功能 输入流 字节流 过滤流
ObjectOutputStream 写出引用数据类型的功能 输出流 字节流 过滤流
*: 作为过滤流的它们 是为了给原本的流添加读写对象的功能的
*: 作为过滤流的它们 不能直接连接文件 只能连接其它的流
*: ObjectInputStream 核心方法 readObject() 有返回值
*: ObjectOutputStream 核心方法 writeObject() 要参数
*: ObjectInputStream 同样不以-1作为读取结束的标识
而是一旦到达文件结尾 再继续尝试读取
将会直接触发EOFException => End Of File
*: 想要持久化 必须先要序列化
想要持久化到磁盘上的对象的类型 必须实现序列化接口
**implements Serializable**
如果要持久化的对象当中有其它引用类型的属性
这些属性的类型也必须实现序列化接口
如果某些属性无关紧要 不需要参与持久化
可以使用transient修饰
transient = 短暂的 转瞬即逝的 不参与持久化的
*: 如果要持久化保存的是一个集合对象
则必须保证集合当中存放的元素的类型都实现了序列化接口
如果是个使用了比较器的TreeSet或者TreeMap
就连比较器的类型也必须要实现序列化接口
(因为比较器是TreeSet或者TreeMap的一个属性)
## 字符IO流
Reader 所有字符输入流统一的父类 抽象类
int read()
int read(char[] data)
int read(char[] data,int off,int len)
Writer 所有字符输出流统一的父类 抽象类
write(int data)
write(char[] data)
write(char[] data,int off,int len)
FileReader 字符流 输入流 节点流
FileWriter 字符流 输出流 节点流
*: 它们都是节点流 构造方法允许传入String路径 / File对象
*: 尽管他们都是节点流 但是只能连接文件不能连接目录
否则直接触发FileNotFoundException
*: FileReader 最常用的是read(char[])
*: FileWriter 最常用的却是write(char[],int,int)
*: FileWriter 同样是个节点输出流
节点输出流创建对象的时候 如果连接的文件不存在
也会自己创建出来
但是如果连接的目录结构都不存在 将直接异常
节点输出流是具有极强的杀伤性的
创建对象的时候 如果连接的文件已经存在
也会在创建的那一刻 被新的空白文件直接覆盖
如果需求是在原有内容的最后 继续追加新内容
则构造方法传参 指定追加模式:
new FileWriter("a.txt",true);
*: FileReader 以-1作为读取结束的标识
*: 用完流第一时间关流 以解除文件的占用状态
BufferedReader 输入流 字符流 过滤流 *****
BufferedWriter 输出流 字符流 过滤流
*: 作为过滤流的它们 是为了给原本的流添加变长的缓冲空间
从而实现以一行(hang)为单位的读写
*: 作为过滤流的它们 不能直接连接文件 只能连接其它的流
*: BufferedReader String readLine()
*: BufferedWriter write(String str) + newLine()
*: BufferedReader 以null作为读取结束的标识
*: BufferedWriter 是带缓冲区的输出流
请务必注意及时清空缓冲 以防止数据滞留缓冲空间
1> 满了自动清空
2> 关闭流的操作触发清空缓冲
3> flush();
PrintWriter 比 BufferedWriter 强大在哪些方面
*:PrintWriter 既可以当做节点流 又可以当做过滤流
构造方法允许传入 String路径 / File文件 / 流
*:PrintWriter 既可以连接字节流 又可以连接字符流
构造方法允许传入 OutputStream / Writer
*:**当做节点流使用的时候 构造方法第二个参数**
**可以指定字符编码**
new PrintWriter("a.txt","**utf-8**");
*:**当做过滤流使用的时候 构造方法第二个参数**
**允许指定自动清空缓冲**
new PrintWriter(new FileWriter("a.txt"),**true**); //AutoFlush
*:它的一个 println() == write() + newLine()
*:我们对它的孪生兄弟 非常熟悉 System.out PrintStream
```Java
综上所述 我们需要以一行为单位写出文本文件的时候
不会使用BufferedWriter 而会使用PrintWriter
```
## 小补充
01.能再解释一遍 FileInputStream 和 BufferedInputStream
为什么以-1作为读取结束的标识
但是DataInputStream不行?
```java
FileInputStream和BufferedInputStream 的read()返回的是编码
编码是不会有-1的 所以可以利用-1作为结束的标识
DataInputStream 它能够读取基本数据类型
byte short int long 四种类型都可能会出现-1的值
如果用-1作为结束标识 那么真读到-1咋办呢
```
02.HelloWorld限次执行10次 收费的那个return可以不用写吗?
不是非得加return 但是要控制后界面的代码逻辑不执行
要么return 要么else~
03.
File[] ds = tar.listFiles((x) -> x.isDirectory());
File[] fs = tar.listFiles((x) -> x.isFile());
if(ds == null) return;
```java
这其中为什么一个为空就可以结束
你的ds 和 fs 其实都是tar.listFiles()得到的
它们在tar代表的那个目录没有权限的情况下 会直接返回null
如果fs是null 则ds必然也是null
```
# day04 复习
## 两个异常
01.文件复制目标文件出现 “ 过大 ” 或者 “ 过小 ” 是由于什么原因造成的
过大:没有使用三参数的write(byte[],int,int)
我们应该实际读取到多少个字节就写出多少字节
不能把整个数组都直接写出
过小:使用了带缓冲区的输出流 没有及时清空缓冲
02.再讲一下InvalidClassException是在什么条件下触发的?
写出对象的时候和读取对象的时候
类当中属性或方法做了修改 所以导致**序列化的唯一编号**
**前后不一致**!
## InputStreamReade 桥转换器
```java
FileInputStream fis = new FileInputStream("abc.txt");
InputStreamReader r = new InputStreamReader(fis,"utf-8");
BufferedReader br = new BufferedReader(r);
```
## RandomAccessFile
RandomAccessFile 既是字节输入流,又是字节输出流,是节点流。
```java
RandomAccessFile raf = new RandomAccessFile("d:\etoak.mp4","rw"); //设置"rw" 代表读写功能
raf.setLength(50L<<30); //设置文件大小,L是为了防止内存溢出而加的 不加L会报异常
raf.close();
```
## 拓展
```java
URL url = new URL("http://old.etoak.com/assets/images/zkcs.png");
URLConnection uc = url.openConnection();
InputStream is = uc.getInputStream();
```
# day05
**Stream流,是Java8的新特性,可以修改集合流中的数据但是不会改变原先集合中的数据**
## Stream流使用案例(lambda表达式必会)
单列集合:集合对象.stream()
```java
List<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream();
```
数组:Arrays.stream(数组) 或者 使用Stream.of()来创建
```java
Integer []arr={1,2,3,4};
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> stream = Stream.of(arr);
```
双列集合:转换成单列集合后再创建
```java
//map集合获取Steam流的方式 map.entrySet().stream();
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Stream<Map.Entry<String, Integer>> thisMap = entries.stream();
```
## 案例一:List集合获取流
```java
/**
使用Steam流过滤掉List集合中不符合条件的数据
将过滤后的数据添加到新的集合当中去
**/
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
List<Integer> aList = new ArrayList<>();
for (int i=0;i<10;i++){
if (i==5)
list.add(i);
if (i==6)
list.add(i);
list.add(i);
}
list.forEach(integer -> System.out.print(" " + integer));
//单列集合(例如List)获取流的方式 list.stream();
list.stream()
.distinct() //去重
.filter(integer -> integer>7) //根据条件过滤
.forEach(integer -> aList.add(integer)); //遍历并进行相关操作
aList.forEach(integer -> System.out.println("integer = " + integer));
}
```
## 案例二:Map集合获取流
```java
/**
根据条件对map集合进行筛选
**/
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("大一",18000);
map.put("大二",18500);
map.put("大三",19000);
map.put("大四",20000);
//map集合获取Steam流的方式 map.entrySet().stream();
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Stream<Map.Entry<String, Integer>> thisMap = entries.stream();
thisMap.filter(entry -> entry.getValue()> 18666)
.forEach(entry -> System.out.println(entry.getKey()+" "+entry.getValue()));
}
```
## 案例三:List集合流map()的使用
```java
/**
将List流中的数据进行转换
即将原先流中的Student类型的数据转换成String类型
**/
public class LambdaAndStreamT3 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三",18,'男'));
list.add(new Student("李四",22,'男'));
list.add(new Student("王五",25,'男'));
list.stream()
.filter(student -> student.getAge()>20)
.map(student -> student.getName())
.forEach(s -> System.out.println("name = " + s));
}
}
@Data
@AllArgsConstructor
class Student{
private String name;
private int age;
private char sex;
}
```
**distinct()方法的使用,底层依靠的是Object的equals()方法**
返回由该流的不同元素(根据 Object.equals(Object) )组成的流。
## 案例四:使用sorted方法进行排序
**sorted()方法可以对流中的元素进行排序,并且要求流中不能有重复的元素**
先去重,后排序
**注意**:如果调用空参的sorted()方法,需要流中的元素是实现了Comparable接口
```java
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i=0;i<10;i++){
if (i==5)
list.add(i);
if (i==6)
list.add(i);
list.add(i);
}
list.add(18);
list.add(22);
list.add(11);
list.stream()
.distinct()
.sorted((o1, o2) -> o1 - o2)
.forEach(integer -> System.out.println("integer = " + integer));
}
================================================================================================
```
## 案例五:limit()方法可设置流的最大长度,超出部分将被抛弃
```java
/**
* 对流中的元素按照年龄进行排序
* 并且要求不能有重复的元素
* 然后打印其中年龄最大的两名作家的姓名。
*/
public class LambdaAndStreamT4 {
public static void main(String[] args) {
List<Teacher> list = new ArrayList<>();
list.add(new Teacher("张三",29,'女'));
list.add(new Teacher("王五",38,'男'));
list.add(new Teacher("赵六",27,'男'));
list.add(new Teacher("老八",32,'男'));
list.add(new Teacher("李四",42,'男'));
list.stream()
.distinct()
.sorted((t1, t2) -> t2.getAge() - t1.getAge())
.limit(2)
.forEach(teacher -> System.out.println("teacher = " + teacher));
}
}
@Data
@AllArgsConstructor
class Teacher{
private String name;
private int age;
private char sex;
}
```
## 案例六:skip(n)方法,跳过流中的前n个元素,返回剩下元素
```java
/**
* 打印除了年龄最大的作家外的其他作家
* 要求不能有重复元素
* 并且按照年龄降序排序
*/
public class LambdaAndStreamT5 {
public static void main(String[] args) {
List<Man> list = new ArrayList<>();
list.add(new Man("张三",29,'女'));
list.add(new Man("王五",38,'男'));
list.add(new Man("赵六",27,'男'));
list.add(new Man("赵六",27,'男'));
list.add(new Man("李四",42,'男'));
list.stream()
.distinct()
.sorted((m1,m2)->m2.getAge()-m1.getAge())
.skip(1)
.forEach(man -> System.out.println("man = " + man));
}
}
@Data
@AllArgsConstructor
class Man{
private String name;
private int age;
private char sex;
}
```
**PrintStream PrintWriter**
# day07
java.net.Socket => 套接字
一根电话线 .. 包含两股线
CS架构的软件:
Client - Server 客户端和服务器
## 服务器端:
0.预留一个线程池执行器
1.创建ServerSocket对象
2.循环当中不停的调用ServerSocket的accept()接收客户端连接
3.将Socket连接对象 委托给一个线程 并且将线程提交给执行器
*: 根据需求得到对应的输入流或者输出流
*: 对流进行相应的包装和处理 (包装流)
*: 调用对应流的对应的核心方法 读写数据
*: 关关关
## 客户端:
1.直接创建Socket对象 并且指定要连接的IP地址和端口号
2.根据需求得到对应的输入流或者输出流
3.对流进行相应的包装和处理 (包装流)
4.调用对应流的对应的核心方法 读写数据
5.关关关
## 练习1:客户端服务器相互传数据
```java
/**
* 服务器获取客户端传来的歌曲名
* 然后服务器找到该文件
* 接下来服务器将该文件
*/
public class ServerTest7 {
public static void main(String[] args) throws Exception {
//创建一个60025端口的Socket对象
ServerSocket socket = new ServerSocket(60025);
//创建连接池对象
ExecutorService ec = Executors.newCachedThreadPool();
//创建一个标记服务器运行状态的布尔值
boolean isRunning = true;
while (isRunning) {
//服务器阻塞在此
Socket waiter = socket.accept();
//创建
MyServerTestThread mst = new MyServerTestThread(waiter);
ec.submit(mst);
}
ec.shutdown();
socket.close();
}
}
class MyServerTestThread extends Thread {
private Socket socket;
public MyServerTestThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//获取输入流,拿到客户端传来的歌曲名
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String name = br.readLine();
//创建文件对象
File dir = new File("D:\\11\\day07\\MusicPlatform\\mp3");
//拿到以.MP3结尾的歌曲文件
File[] files = dir.listFiles(f -> f.isFile() && f.getName().toLowerCase().endsWith(".mp3"));
//遍历files对象数组
for (File file : files) {
//拿到遍历的文件名
String name1 = file.getName();
String name2 = name1.substring(0, name1.lastIndexOf("."));
//对比文件名 如果相同那么读文件 然后将文件写出到客户端
if (name2.equals(name)) {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bos.close();
bis.close();
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
```java
package com.ls.test1;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* 向服务器传输歌曲名
* 获取服务器返回的数据
* 并保存到d:\\11目录下的aaa.MP3
*/
public class ClientTest7 {
public static void main(String[] args) throws Exception {
Socket socket = new Socket(InetAddress.getLocalHost(),7777);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
Scanner input = new Scanner(System.in);
String name = input.nextLine();
pw.println(name);
System.out.println("name = " + name);
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\11\\aaa.mp3"));
byte []bytes=new byte[1024];
int len;
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
pw.close();
input.close();
socket.close();
}
}
```