IO/NIO 例子

题目:

     passport日志由以下三个字段组成,用户名、访问时间、访问者的IP地址。 要求在passport日志中进行以下操作:

    1、找到访问次数最多的用户名,并求出访问次数

    2、找到指定用户的访问记录

   要求用IO/NIO实现


思路如下:

  (1)首先将文件读进来,一行一行的处理

  (2)对每一行,将姓名作为key,访问的记录对象作为value存入HashMap<String,List<访问的记录对象>>

  (3)在这个HashMap中做操作即可


代码如下:

封装的访问详情对象:

public class Passport {
    private String name;
    private Long time;
    private String ip;

    public Passport(String name, Long time, String ip) {
        this.name = name;
        this.time = time;
        this.ip = ip;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }
}


IO访问接口:

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

public interface CommonFAO {
    // 读文件,返回一个key为name,value为Passport对象的HashMap
    public HashMap<String, List<Passport>> read(String fileName) throws IOException;
}


BIO的实现:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class BIOFAOImpl implements CommonFAO {

    @Override
    public HashMap<String, List<Passport>> read(String fileName) throws IOException {
        HashMap<String, List<Passport>> map = new HashMap<>();
        BufferedReader br = new BufferedReader(new FileReader(fileName));
        String str;
        while ((str = br.readLine()) != null) {
            String[] words = str.split("\t");
            Passport pp = new Passport(words[0], Long.parseLong(words[1]), words[2]);
            if (map.containsKey(words[0])) {
                map.get(words[0]).add(pp);
            } else {
                List<Passport> list = new ArrayList<>();
                list.add(pp);
                map.put(words[0], list);
            }
        }
        return map;
    }
}

NIO的实现:

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class NIOFAOImpl implements CommonFAO {

    @Override
    public HashMap<String, List<Passport>> read(String fileName) throws IOException {
        HashMap<String, List<Passport>> map = new HashMap<>();
        RandomAccessFile aFile = new RandomAccessFile(fileName, "rw");
        java.nio.channels.FileChannel inChannel = aFile.getChannel();
        // 根据FileChannel的大小创建缓冲区
        ByteBuffer buf = ByteBuffer.allocate((int) inChannel.size());
        // 写到缓冲区
        inChannel.read(buf);
        // 切换缓冲区模式为读模式
        buf.flip();
        byte[] content = new byte[(int) inChannel.size()];
        // 将缓冲区内的内容读到byte[]数组
        buf.get(content, 0, (int) inChannel.size());
        // 将byte数组转为String
        String str = new String(content);
        // 切分为一行一行的句子
        String[] lines = str.split("\n");
        // 遍历一行一行的句子,逐个处理并扔到HashMap
        for (String line : lines) {
            String[] words = line.split("\t");
            Passport pp = new Passport(words[0], Long.parseLong(words[1]), words[2]);
            if (map.containsKey(words[0])) {
                map.get(words[0]).add(pp);
            } else {
                List<Passport> list = new ArrayList<>();
                list.add(pp);
                map.put(words[0], list);
            }
        }
        aFile.close();

        return map;
    }

}

service接口:

import java.io.IOException;
import java.util.List;


public interface Service {
    // 找出登陆次数最多的用户名字name,并返回登陆次数
    public Result loginNum(String fileName) throws IOException;


    // 找出某个用户所有的登录记录
    public List<Passport> loginRecord(String fileName, String name) throws IOException;
}

service的实现

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

public class ServiceImpl implements Service {
    private CommonFAO commFao = new BIOFAOImpl();// new NIOFAOImpl()
    HashMap<String, List<Passport>> map;

    @Override
    public Result loginNum(String fileName) throws IOException {
        map = commFao.read(fileName);
        Set<Entry<String, List<Passport>>> entrySet = map.entrySet();
        int num = Integer.MIN_VALUE;
        String name = null;
        for (Entry<String, List<Passport>> entry : entrySet) {
            if (entry.getValue().size() > num) {
                num = entry.getValue().size();
                name = entry.getKey();
            }
        }
        return new Result(name, num);
    }

    @Override
    public List<Passport> loginRecord(String fileName, String name) throws IOException {
        map = commFao.read(fileName);
        return map.get(name);
    }

}

返回值对象包含次数和用户名:

public class Result {
    private String name;
    private int num;

    public Result(String name, int num) {
        this.name = name;
        this.num = num;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

}

入口函数:

import java.io.IOException;
import java.util.List;

public class PasspartTest {

    public static void main(String[] args) throws IOException {
        Service service = new ServiceImpl();
        String fileName = "/Users/bjhl/passport.log";
        Result result = service.loginNum(fileName);
        System.out.println("最多登录者是: " + result.getName() + ",登陆次数为" + result.getNum() + "次");

        List<Passport> list = service.loginRecord(fileName, "wangfan");
        System.out.println("登录者wangfan的详细信息为:");
        for (Passport passport : list) {
            System.out
                .println("登录名:" + passport.getName() + ",登录时间:" + passport.getTime() + "登录IP:" + passport.getIp());
        }
    }
}

测试文件内容:(制表符隔开)

wangfan	123456754	1.2.3.4
wangfan1	133456754	2.2.3.4
wangfan2	123446754	1.5.3.4
wangfan3	127456754	1.7.3.4
wangfan4	128456754	1.8.3.4
wangfan5	123456754	3.2.3.4
wangfan6	123456754	5.2.3.4
wangfan7	123456754	6.2.3.4
wangfan8	123456754	7.2.3.4
wangfan9	123456754	1.2.3.5
wangfan	123456756	1.2.3.4
wangfan	123756754	1.8.3.4
wangfan	129456754	1.9.3.4
wangfan	183456754	1.2.9.4
wangfan	193456754	1.2.6.4

运行效果:



### Java IO流与NIO使用教程及区别 #### 一、基本概念 Java 提供了两种主要的 I/O API:传统 IONIO。传统 IO 主要基于字节流和字符流,通过 `InputStream` 和 `OutputStream` 进行读写操作;而 NIO 则围绕着通道(Channel)、缓冲区(Buffer)和选择器(Selector),采用更高效的方式处理数据传输。 对于传统 IO 而言,其设计较为简单直观,适用于大多数常规文件或网络通信需求[^1]。然而,在面对大规模并发连接或者实时性强的应用场景时,则显得力不从心。相比之下,NIO 的非阻塞特性及其多路复用机制能够更好地满足这类特殊场合下的性能要求[^2]。 #### 二、具体实现方式 ##### (一)传统 IO 流的操作方法 下面是一个简单的例子来展示如何利用传统的 FileInputSteam 来读取本地磁盘上的文本文件: ```java import java.io.*; public class TraditionalIOExample { public static void main(String[] args) throws IOException { String filePath = "example.txt"; try (FileInputStream fis = new FileInputStream(filePath); InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr)) { String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { throw new RuntimeException(e); } } } ``` 这段代码展示了怎样打开一个文件并逐行打印其中的内容。这里需要注意的是每次调用 readLine() 方法都会导致程序暂停执行直到有新的输入到达为止—这就是所谓的“阻塞性”。 ##### (二)NIO 的应用实例 接下来再看一段关于 NIO示例代码,它同样实现了相同的功能但是采用了不同的思路: ```java import java.nio.file.*; import java.nio.charset.StandardCharsets; public class NIOWithFilesExample { public static void main(String[] args) throws Exception { Path path = Paths.get("example.txt"); Files.lines(path, StandardCharsets.UTF_8).forEach(System.out::println); } } ``` 此版本不仅更加简洁明了而且效率更高因为它是批量加载整个文档而不是一行一行地解析。更重要的是如果想要构建一个多线程服务器端应用程序的话那么就可以充分利用到 NIO 所提供的非阻塞特性和 Selector 组件从而大大提升系统的吞吐量[^3]。 #### 三、两者的主要差异点 | 特征 | Java IO | Java NIO | | --- | --- | --- | | 面向的对象 | 字符串/字节数组 | 缓冲区(Buffer) | | 操作模式 | 阻塞式 | 支持非阻塞式 | | 是否支持多路复用 | 否 | 是 | 上述表格清晰地概括出了二者之间最核心的区别之处[^4]。除此之外还有其他方面的不同比如资源管理方面等等。总体来说当涉及到高负载环境或者是需要频繁切换状态的任务时应该优先考虑使用 NIO 技术栈以获得更好的响应速度和服务质量。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值