Vra

Hoewel googlen, sien ek dat die gebruik van java.io.File#length() kan stadig wees. FileChannel het 'n size() metode wat beskikbaar is sowel.

Is daar 'n doeltreffende manier in Java na die grootte van die lêer te kry?

Was dit nuttig?

Oplossing

Wel, ek het probeer om dit op te meet met die onderstaande kode:

Vir lopies = 1 en iterasies = 1 die URL metode is die vinnigste mees tye gevolg deur kanaal. Ek hardloop hierdie met 'n paar breek vars sowat 10 keer. So vir 'n tyd toegang, met behulp van die URL is die vinnigste manier wat ek kan dink:

LENGTH sum: 10626, per Iteration: 10626.0

CHANNEL sum: 5535, per Iteration: 5535.0

URL sum: 660, per Iteration: 660.0

Vir lopies = 5 en iterasies = 50 die prentjie trek anders.

LENGTH sum: 39496, per Iteration: 157.984

CHANNEL sum: 74261, per Iteration: 297.044

URL sum: 95534, per Iteration: 382.136

Lêer moet kas die oproepe na die lêerstelsel, terwyl kanale en URL het 'n paar oorhoofse.

Kode:

import java.io.*;
import java.net.*;
import java.util.*;

public enum FileSizeBench {

    LENGTH {
        @Override
        public long getResult() throws Exception {
            File me = new File(FileSizeBench.class.getResource(
                    "FileSizeBench.class").getFile());
            return me.length();
        }
    },
    CHANNEL {
        @Override
        public long getResult() throws Exception {
            FileInputStream fis = null;
            try {
                File me = new File(FileSizeBench.class.getResource(
                        "FileSizeBench.class").getFile());
                fis = new FileInputStream(me);
                return fis.getChannel().size();
            } finally {
                fis.close();
            }
        }
    },
    URL {
        @Override
        public long getResult() throws Exception {
            InputStream stream = null;
            try {
                URL url = FileSizeBench.class
                        .getResource("FileSizeBench.class");
                stream = url.openStream();
                return stream.available();
            } finally {
                stream.close();
            }
        }
    };

    public abstract long getResult() throws Exception;

    public static void main(String[] args) throws Exception {
        int runs = 5;
        int iterations = 50;

        EnumMap<FileSizeBench, Long> durations = new EnumMap<FileSizeBench, Long>(FileSizeBench.class);

        for (int i = 0; i < runs; i++) {
            for (FileSizeBench test : values()) {
                if (!durations.containsKey(test)) {
                    durations.put(test, 0l);
                }
                long duration = testNow(test, iterations);
                durations.put(test, durations.get(test) + duration);
                // System.out.println(test + " took: " + duration + ", per iteration: " + ((double)duration / (double)iterations));
            }
        }

        for (Map.Entry<FileSizeBench, Long> entry : durations.entrySet()) {
            System.out.println();
            System.out.println(entry.getKey() + " sum: " + entry.getValue() + ", per Iteration: " + ((double)entry.getValue() / (double)(runs * iterations)));
        }

    }

    private static long testNow(FileSizeBench test, int iterations)
            throws Exception {
        long result = -1;
        long before = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            if (result == -1) {
                result = test.getResult();
                //System.out.println(result);
            } else if ((result = test.getResult()) != result) {
                 throw new Exception("variance detected!");
             }
        }
        return (System.nanoTime() - before) / 1000;
    }

}

Ander wenke

Die maatstaf gegee deur GHad meet baie ander dinge (soos besinning, instantiëren voorwerpe, ens) behalwe om die lengte. As ons probeer om ontslae te raak van hierdie dinge dan vir een oproep wat ek kry die volgende keer in mikrosekondes:

   file sum___19.0, per Iteration___19.0
    raf sum___16.0, per Iteration___16.0
channel sum__273.0, per Iteration__273.0

Vir 100 lopies en 10000 iterasies ek kry:

   file sum__1767629.0, per Iteration__1.7676290000000001
    raf sum___881284.0, per Iteration__0.8812840000000001
channel sum___414286.0, per Iteration__0.414286

Ek het die volgende gewysigde kode gee as 'n argument die naam van 'n 100MB-lêer uit te voer.

import java.io.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;

public class FileSizeBench {

  private static File file;
  private static FileChannel channel;
  private static RandomAccessFile raf;

  public static void main(String[] args) throws Exception {
    int runs = 1;
    int iterations = 1;

    file = new File(args[0]);
    channel = new FileInputStream(args[0]).getChannel();
    raf = new RandomAccessFile(args[0], "r");

    HashMap<String, Double> times = new HashMap<String, Double>();
    times.put("file", 0.0);
    times.put("channel", 0.0);
    times.put("raf", 0.0);

    long start;
    for (int i = 0; i < runs; ++i) {
      long l = file.length();

      start = System.nanoTime();
      for (int j = 0; j < iterations; ++j)
        if (l != file.length()) throw new Exception();
      times.put("file", times.get("file") + System.nanoTime() - start);

      start = System.nanoTime();
      for (int j = 0; j < iterations; ++j)
        if (l != channel.size()) throw new Exception();
      times.put("channel", times.get("channel") + System.nanoTime() - start);

      start = System.nanoTime();
      for (int j = 0; j < iterations; ++j)
        if (l != raf.length()) throw new Exception();
      times.put("raf", times.get("raf") + System.nanoTime() - start);
    }
    for (Map.Entry<String, Double> entry : times.entrySet()) {
        System.out.println(
            entry.getKey() + " sum: " + 1e-3 * entry.getValue() +
            ", per Iteration: " + (1e-3 * entry.getValue() / runs / iterations));
    }
  }
}

Alle toets gevalle in hierdie post die is gebrekkig as hulle dieselfde lêer toegang vir elke toets metode. So skyf kas skop waarop toetse 2 en 3 voordeel trek uit. Om my punt te bewys het ek toetssaak wat deur GHAD en verander die volgorde van opsomming en onder is die resultate.

As ons kyk na resultaat Ek dink File.length () is die wenner regtig.

Orde van toets is aan die orde van uitset. Jy kan selfs sien die tyd wat dit neem op my masjien het gewissel tussen teregstellings maar File.Length () toe nie eers sit en aangaan eerste toegang skyf gewen.

---
LENGTH sum: 1163351, per Iteration: 4653.404
CHANNEL sum: 1094598, per Iteration: 4378.392
URL sum: 739691, per Iteration: 2958.764

---
CHANNEL sum: 845804, per Iteration: 3383.216
URL sum: 531334, per Iteration: 2125.336
LENGTH sum: 318413, per Iteration: 1273.652

--- 
URL sum: 137368, per Iteration: 549.472
LENGTH sum: 18677, per Iteration: 74.708
CHANNEL sum: 142125, per Iteration: 568.5

As ek jou kode om 'n lêer geopen deur 'n absolute pad in plaas van 'n hulpbron gebruik te verander, kry ek 'n ander resultaat (vir 1 lopie, 1 iterasie, en 'n 100,000 byte lêer - keer vir 'n 10 byte lêer identies 100,000 bytes)

LENGTE som: 33, per iterasie: 33.0

CHANNEL som: 3626, per iterasie: 3626,0

URL som: 294 per iterasie: 294,0

In reaksie op maatstaf rgrig se die tyd wat dit neem om oop te maak / te sluit die FileChannel & RandomAccessFile gevalle ook nodig in ag geneem moet word, aangesien hierdie klasse 'n stroom sal oopmaak vir die lees van die lêer.

Na die wysiging van die maatstaf, ek het hierdie resultate vir 1 iterasies op 'n 85MB lêer:

file totalTime: 48000 (48 us)
raf totalTime: 261000 (261 us)
channel totalTime: 7020000 (7 ms)

Vir 10000 iterasies op dieselfde lêer:

file totalTime: 80074000 (80 ms)
raf totalTime: 295417000 (295 ms)
channel totalTime: 368239000 (368 ms)

As alles wat jy nodig het, is die grootte van die lêer, file.length () is die vinnigste manier om dit te doen. As jy van plan is om die lêer vir ander doeleindes soos lees / skryf gebruik, dan RAF lyk na 'n beter bet. Moet net nie vergeet om die lêer verband sluit: -)

import java.io.File;
import java.io.FileInputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;

public class FileSizeBench
{    
    public static void main(String[] args) throws Exception
    {
        int iterations = 1;
        String fileEntry = args[0];

        Map<String, Long> times = new HashMap<String, Long>();
        times.put("file", 0L);
        times.put("channel", 0L);
        times.put("raf", 0L);

        long fileSize;
        long start;
        long end;
        File f1;
        FileChannel channel;
        RandomAccessFile raf;

        for (int i = 0; i < iterations; i++)
        {
            // file.length()
            start = System.nanoTime();
            f1 = new File(fileEntry);
            fileSize = f1.length();
            end = System.nanoTime();
            times.put("file", times.get("file") + end - start);

            // channel.size()
            start = System.nanoTime();
            channel = new FileInputStream(fileEntry).getChannel();
            fileSize = channel.size();
            channel.close();
            end = System.nanoTime();
            times.put("channel", times.get("channel") + end - start);

            // raf.length()
            start = System.nanoTime();
            raf = new RandomAccessFile(fileEntry, "r");
            fileSize = raf.length();
            raf.close();
            end = System.nanoTime();
            times.put("raf", times.get("raf") + end - start);
        }

        for (Map.Entry<String, Long> entry : times.entrySet()) {
            System.out.println(entry.getKey() + " totalTime: " + entry.getValue() + " (" + getTime(entry.getValue()) + ")");
        }
    }

    public static String getTime(Long timeTaken)
    {
        if (timeTaken < 1000) {
            return timeTaken + " ns";
        } else if (timeTaken < (1000*1000)) {
            return timeTaken/1000 + " us"; 
        } else {
            return timeTaken/(1000*1000) + " ms";
        } 
    }
}

Ek het in hierdie selfde probleem. Ek nodig het om die grootte van die lêer en gewysigde datum van 90.000 lêers op 'n netwerk aandeel kry. Die gebruik van Java, en om as minimalistische as moontlik, sal dit 'n baie lang tyd in beslag neem. (Ek nodig het om die URL van die lêer, en die pad van die voorwerp sowel kry. So sy ietwat gewissel, maar meer as 'n uur.) Dan gebruik ek 'n boorling Win32 uitvoerbare, en het dieselfde taak, net storting die lêer pad, verander, en grootte na die konsole, en uitgevoer word dat van Java. Die spoed was amazing. Die boorling proses, en my string hantering om die data te lees kan meer as 1000 items 'n tweede verwerk.

So selfs al mense af posisie van die bogenoemde kommentaar, dit is 'n geldige oplossing, en het my probleem op te los. In my geval het ek geweet die dopgehou wat ek nodig het die groottes van voor die tyd, en ek kon slaag wat in die command line om my win32 app. Ek het van uur tot 'n gids tot minute verwerk.

Die kwessie het ook lyk Windows spesifiek te wees. OS X het dieselfde probleem nie en kan toegang netwerk lêer inligting so vinnig as wat die bedryfstelsel so kan doen.

Java lêerhantering op Windows is verskriklik. Plaaslike toegang skyf vir lêers is al goed. Dit is net te netwerk aandele wat die verskriklike prestasie veroorsaak. Windows kan besonderhede oor die netwerk te deel en bereken die totale grootte in onder 'n minuut te.

- Ben

As jy die grootte van die lêer van veelvuldige lêers wil in 'n gids, gebruik Files.walkFileTree . Jy kan die grootte van die BasicFileAttributes wat jy ontvang bekom.

Dit is baie vinniger as 'n beroep .length() op die uitslag van File.listFiles() of die gebruik van Files.size() op die uitslag van Files.newDirectoryStream(). In my toets gevalle was dit sowat 100 keer vinniger.

Eintlik, dink ek die "ls" kan vinniger wees. Daar is beslis 'n paar kwessies in Java wat handel oor die maak van lêer inligting. Ongelukkig is daar geen ekwivalent veilige metode van rekursiewe ls vir Windows. (Cmd.exe se DIR / S kan deurmekaar raak en genereer foute in oneindige lusse)

Op XP, toegang tot 'n bediener op die LAN, dit neem my 5 sekondes in Windows op die telling van die lêers te kry in 'n gids (33000), en die totale grootte.

Wanneer ek rekursief Itereer deur middel van hierdie in Java, dit neem my meer as 5 minute. Ek het begin meet die tyd wat dit neem om file.length (doen), file.lastModified (), en file.toURI () en wat is dit 99% van my tyd geneem word deur diegene 3 oproepe het ek gevind. Die 3 oproepe wat ek nodig het eintlik te doen ...

Die verskil vir 1000 lêers is 15ms plaaslike versus 1800ms op bediener. Die bediener pad skandering in Java is belaglik stadig. As die inheemse OS vinnig by skandering kan wees dat dieselfde gids, waarom kan nie Java?

As 'n meer volledige toets, gebruik ek WineMerge op XP na die gewysigde datum en grootte van die lêers te vergelyk op die bediener teenoor die lêers plaaslik. Dit was iterating oor die hele gids boom van 33.000 lêers in elke gids. Totale tyd, 7 sekondes. java:. meer as 5 minute

So het die oorspronklike verklaring en vraag van die OP is waar, en geldig. Sy minder opvallend wanneer die hantering van 'n plaaslike lêer stelsel. Doen 'n plaaslike vergelyk van die gids met 33,000 items neem 3 sekondes in WinMerge, en neem 32 sekondes plaaslik in Java. So weer, Java versus moedertaal is 'n 10x verlangsaming in hierdie basiese toetse.

Java 1.6.0_22 (nuutste), Gigabit LAN, en netwerk verbindings, ping is minder as 1ms (beide in dieselfde skakelaar)

Java is stadig.

Van maatstaf GHad se, daar is 'n paar kwessie mense het genoem:

1> Soos BalusC genoem: stream.available () is gevloei in hierdie geval.

As gevolg beskikbaar () gee terug 'n skatting van die aantal grepe wat gelees kan word (of oorgeslaan oor) van hierdie inset stroom sonder blokkeer deur die volgende aanroeping van 'n metode vir hierdie inset stroom.

So 1 tot die URL hierdie benadering te verwyder.

2> As StuartH genoem -. Die einde van die toets lopie ook die kas verskil te maak, so neem dat deur afsonderlik loop die toets


Nou begin toets:

Wanneer CHANNEL een lopie alleen:

CHANNEL sum: 59691, per Iteration: 238.764

Wanneer LENGTE een lopie alleen:

LENGTH sum: 48268, per Iteration: 193.072

So lyk die lengte een is die wenner hier:

@Override
public long getResult() throws Exception {
    File me = new File(FileSizeBench.class.getResource(
            "FileSizeBench.class").getFile());
    return me.length();
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top