亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java實(shí)現(xiàn)讀取超過(guò)內(nèi)存大小的文件

 更新時(shí)間:2024年03月29日 16:05:55   作者:程序猿DD  
在一些場(chǎng)景下,我們需要處理的文件可能比我們機(jī)器所擁有的內(nèi)存要大,如果遇到這種情況該如何解決呢,本文就來(lái)和大家講講如何使用Java實(shí)現(xiàn)讀取超過(guò)內(nèi)存大小的文件吧

讀取文件內(nèi)容,然后進(jìn)行處理,在Java中我們通常利用 Files 類中的方法,將可以文件內(nèi)容加載到內(nèi)存,并流順利地進(jìn)行處理。但是,在一些場(chǎng)景下,我們需要處理的文件可能比我們機(jī)器所擁有的內(nèi)存要大。此時(shí),我們則需要采用另一種策略:部分讀取它,并具有其他結(jié)構(gòu)來(lái)僅編譯所需的數(shù)據(jù)。

接下來(lái),我們就來(lái)說(shuō)說(shuō)這一場(chǎng)景:當(dāng)遇到大文件,無(wú)法一次載入內(nèi)存時(shí)候要如何處理。

模擬場(chǎng)景

假設(shè),當(dāng)前我們需要開(kāi)發(fā)一個(gè)程序來(lái)分析來(lái)自服務(wù)器的日志文件,并生成一份報(bào)告,列出前 10 個(gè)最常用的應(yīng)用程序。

每天,都會(huì)生成一個(gè)新的日志文件,其中包含時(shí)間戳、主機(jī)信息、持續(xù)時(shí)間、服務(wù)調(diào)用等信息,以及可能與我們的特定方案無(wú)關(guān)的其他數(shù)據(jù)。

2024-02-25T00:00:00.000+GMT host7 492 products 0.0.3 PUT 73.182.150.152 eff0fac5-b997-40a3-87d8-02ff2f397b44
2024-02-25T00:00:00.016+GMT host6 123 logout 2.0.3 GET 34.235.76.94 8b97acae-dd36-4e83-b423-12905a4ab38d
2024-02-25T00:00:00.033+GMT host6 50 payments/:id 0.4.6 PUT 148.241.146.59 ac3c9064-4782-46d9-a0b6-69e4d55a5b38
2024-02-25T00:00:00.050+GMT host2 547 orders 1.5.0 PUT 6.232.116.248 2285a81e-c511-41b9-b0ea-a475a0a45805
2024-02-25T00:00:00.067+GMT host4 400 suggestions 0.8.6 DELETE 149.138.227.154 8031b639-700e-4a7c-b257-fcbed0d029ce
2024-02-25T00:00:00.084+GMT host2 644 login 6.90 GET 208.158.145.204 3906a28c-56e4-4e5f-b548-591eab737aa7
2024-02-25T00:00:00.101+GMT host5 339 suggestions 0.8.9 PUT 173.109.21.97 c7dfec8a-5ca8-4d0d-b903-aaf65629fdd0
2024-02-25T00:00:00.118+GMT host9 87 products 2.6.3 POST 220.252.90.140 e5ceef67-2f0f-4c2d-a6d2-c698598aaef2
2024-02-25T00:00:00.134+GMT host0 845 products 9.4.6 GET 136.79.178.188 f28578c1-c37c-47a3-a473-4e65371e0245
2024-02-25T00:00:00.151+GMT host4 675 login 0.89 DELETE 32.159.65.239 d27ff353-e501-43e6-bdce-680d79a07c36

我們的代碼將收到日志文件列表,我們的目標(biāo)是編制一份報(bào)告,列出最常用的 10 個(gè)服務(wù)。但是,要包含在報(bào)告中,服務(wù)必須在提供的每個(gè)日志文件中至少有一個(gè)條目。簡(jiǎn)而言之,一項(xiàng)服務(wù)必須每天使用才有資格包含在報(bào)告中。

基礎(chǔ)實(shí)現(xiàn)

解決這個(gè)問(wèn)題的最初方法是考慮業(yè)務(wù)需求并創(chuàng)建以下代碼:

public void processFiles(final List<File> fileList) {
  final Map<LocalDate, List<LogLine>> fileContent = getFileContent(fileList);
  final List<String> serviceList = getServiceList(fileContent);
  final List<Statistics> statisticsList = getStatistics(fileContent, serviceList);
  final List<Statistics> topCalls = getTop10(statisticsList);

  print(topCalls);
}

該方法接收文件列表作為參數(shù),核心流程如下:

  • 創(chuàng)建一個(gè)包含每個(gè)文件條目的映射,其中Key是 LocalDate,Value是文件行列表。
  • 使用所有文件中的唯一服務(wù)名稱創(chuàng)建字符串列表。
  • 生成所有服務(wù)的統(tǒng)計(jì)信息列表,將文件中的數(shù)據(jù)組織到結(jié)構(gòu)化地圖中。
  • 篩選統(tǒng)計(jì)信息,獲取排名前 10 的服務(wù)調(diào)用。
  • 打印結(jié)果。

可以注意到,這種方法將太多數(shù)據(jù)加載到內(nèi)存中,不可避免地會(huì)導(dǎo)致 OutOfMemoryError

改進(jìn)實(shí)現(xiàn)

就如文章開(kāi)頭說(shuō)的,我們需要采用另一種策略:逐行處理文件的模式。

private void processFiles(final List<File> fileList) {
  final Map<String, Counter> compiledMap = new HashMap<>();

  for (int i = 0; i < fileList.size(); i++) {
    processFile(fileList, compiledMap, i);
  }

  final List<Counter> topCalls =
      compiledMap.values().stream()
          .filter(Counter::allDaysSet)
          .sorted(Comparator.comparing(Counter::getNumberOfCalls).reversed())
          .limit(10)
          .toList();

  print(topCalls);
}
  • 首先,它聲明一個(gè)Map(compiledMap),其中一個(gè)String作為鍵,代表服務(wù)名稱,以及一個(gè)Counter對(duì)象(稍后解釋),它將存儲(chǔ)統(tǒng)計(jì)信息。
  • 接下來(lái),它逐一處理這些文件并相應(yīng)地更新compileMap。
  • 然后,它利用流功能來(lái): 僅過(guò)濾具有全天數(shù)據(jù)的計(jì)數(shù)器;按調(diào)用次數(shù)排序;最后,檢索前 10 名。

在看整個(gè)處理的核心processFile方法之前,我們先來(lái)分析一下Counter類,它在這個(gè)過(guò)程中也起到了至關(guān)重要的作用:

public class Counter {
  @Getter private String serviceName;
  @Getter private long numberOfCalls;
  private final BitSet daysWithCalls;

  public Counter(final String serviceName, final int numberOfDays) {
    this.serviceName = serviceName;
    this.numberOfCalls = 0L;
    daysWithCalls = new BitSet(numberOfDays);
  }

  public void add() {
    numberOfCalls++;
  }

  public void setDay(final int dayNumber) {
    daysWithCalls.set(dayNumber);
  }

  public boolean allDaysSet() {
    return daysWithCalls.stream()
        .mapToObj(index -> daysWithCalls.get(index))
        .reduce(Boolean.TRUE, Boolean::logicalAnd);
  }
}
  • 它包含三個(gè)屬性:serviceName、numberOfCalls 和 daysWithCalls
  • numberOfCalls 屬性通過(guò) add 方法遞增,該方法為 serviceName 的每個(gè)處理行調(diào)用。
  • daysWithCalls 屬性是一個(gè) Java BitSet,一種用于存儲(chǔ)布爾屬性的內(nèi)存高效結(jié)構(gòu)。它使用要處理的天數(shù)進(jìn)行初始化,每個(gè)位代表一天,初始化為 false。
  • setDay 方法將 BitSet 中與給定日期位置相對(duì)應(yīng)的位設(shè)置為 true。

allDaysSet 方法負(fù)責(zé)檢查 BitSet 中的所有日期是否都設(shè)置為 true。它通過(guò)將 BitSet 轉(zhuǎn)換為布爾流,然后使用邏輯 AND 運(yùn)算符減少它來(lái)實(shí)現(xiàn)此目的。

private void processFile(final List<File> fileList, 
                         final Map<String, Counter> compiledMap, 
                         final int dayNumber) {
  try (Stream<String> lineStream = Files.lines(fileList.get(dayNumber).toPath())) {
    lineStream
        .map(this::toLogLine)
        .forEach(
            logLine -> {
              Counter counter = compiledMap.get(logLine.serviceName());
              if (counter == null) {
                counter = new Counter(logLine.serviceName(), fileList.size());
                compiledMap.put(logLine.serviceName(), counter);
              }
              counter.add();
              counter.setDay(dayNumber);
            });

  } catch (final IOException e) {
    throw new RuntimeException(e);
  }
}
  • 該過(guò)程使用Files類的lines方法逐行讀取文件,并將其轉(zhuǎn)換為流。這里的關(guān)鍵特征是lines方法是惰性的,這意味著它不會(huì)立即讀取整個(gè)文件;相反,它會(huì)在流被消耗時(shí)讀取文件。
  • toLogLine 方法將每個(gè)字符串文件行轉(zhuǎn)換為具有用于訪問(wèn)日志行信息的屬性的對(duì)象。
  • 處理文件行的主要過(guò)程比預(yù)期的要簡(jiǎn)單。它從與serviceName關(guān)聯(lián)的compileMap中檢索(或創(chuàng)建)Counter,然后調(diào)用Counter的add和setDay方法。

正如我們所看到的,在 Java 中處理大文件而不將整個(gè)文件加載到內(nèi)存中并不是什么復(fù)雜的事情。 Files類提供了逐行處理文件的方法,我們還可以在文件處理過(guò)程中利用哈希來(lái)存儲(chǔ)數(shù)據(jù),這有助于節(jié)省內(nèi)存。

到此這篇關(guān)于Java實(shí)現(xiàn)讀取超過(guò)內(nèi)存大小的文件的文章就介紹到這了,更多相關(guān)Java讀取超過(guò)內(nèi)存大小的文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java刪除二叉搜索樹(shù)最大元素和最小元素的方法詳解

    Java刪除二叉搜索樹(shù)最大元素和最小元素的方法詳解

    這篇文章主要介紹了Java刪除二叉搜索樹(shù)最大元素和最小元素的方法,結(jié)合實(shí)例形式詳細(xì)分析了java針對(duì)二叉搜索樹(shù)的基本遍歷、查找、判斷、刪除等相關(guān)操作技巧,需要的朋友可以參考下
    2020-03-03
  • Java泛型之上界下界通配符詳解

    Java泛型之上界下界通配符詳解

    這篇文章主要介紹了Java泛型之上界下界通配符詳解,學(xué)習(xí)使用泛型編程時(shí),更令人困惑的一個(gè)方面是確定何時(shí)使用上限有界通配符以及何時(shí)使用下限有界通配符。本文提供一些設(shè)計(jì)代碼時(shí)要遵循的一些準(zhǔn)則。,需要的朋友可以參考下
    2019-06-06
  • 使用java編程從0到1實(shí)現(xiàn)一個(gè)簡(jiǎn)單計(jì)算器

    使用java編程從0到1實(shí)現(xiàn)一個(gè)簡(jiǎn)單計(jì)算器

    這篇文章主要介紹了使用java編程從0到1實(shí)現(xiàn)一個(gè)簡(jiǎn)單計(jì)算器,文章中用代碼實(shí)例講解的很清晰,有感興趣的同學(xué)可以學(xué)習(xí)研究下
    2021-02-02
  • Java開(kāi)發(fā)HashMap?key必須實(shí)現(xiàn)hashCode?equals方法原理

    Java開(kāi)發(fā)HashMap?key必須實(shí)現(xiàn)hashCode?equals方法原理

    這篇文章主要為大家介紹了Java開(kāi)發(fā)HashMap?key必須實(shí)現(xiàn)hashCode?equals方法原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • SpringBoot中@ComponentScan注解過(guò)濾排除不加載某個(gè)類的3種方法

    SpringBoot中@ComponentScan注解過(guò)濾排除不加載某個(gè)類的3種方法

    這篇文章主要給大家介紹了關(guān)于SpringBoot中@ComponentScan注解過(guò)濾排除不加載某個(gè)類的3種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SpringBoot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 通俗講解JVM的類加載機(jī)制

    通俗講解JVM的類加載機(jī)制

    這篇文章主要介紹了JVM的類加載機(jī)制的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-09-09
  • mybatis中返回多個(gè)map結(jié)果問(wèn)題

    mybatis中返回多個(gè)map結(jié)果問(wèn)題

    這篇文章主要介紹了mybatis中返回多個(gè)map結(jié)果問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Eclipse Debug模式的開(kāi)啟與關(guān)閉問(wèn)題簡(jiǎn)析

    Eclipse Debug模式的開(kāi)啟與關(guān)閉問(wèn)題簡(jiǎn)析

    這篇文章主要介紹了Eclipse Debug模式的開(kāi)啟與關(guān)閉問(wèn)題簡(jiǎn)析,同時(shí)向大家介紹了一個(gè)簡(jiǎn)單的debug模式啟動(dòng)不起來(lái)的解決方法,希望對(duì)大家有所幫助。
    2017-10-10
  • Spring使用@Value注解與@PropertySource注解加載配置文件操作

    Spring使用@Value注解與@PropertySource注解加載配置文件操作

    這篇文章主要介紹了Spring使用@Value注解與@PropertySource注解加載配置文件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 關(guān)于Spring BeanPostProcessor的執(zhí)行順序

    關(guān)于Spring BeanPostProcessor的執(zhí)行順序

    這篇文章主要介紹了Spring BeanPostProcessor的執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10

最新評(píng)論