গুগল করার সময়, আমি দেখতে পাচ্ছি যে ব্যবহারটি java.io.File#length()
ধীর হতে পারে।
পাশাপাশি পাওয়া যায় FileChannel
এমন একটি size()
পদ্ধতি রয়েছে ।
ফাইলের আকার পাওয়ার জন্য জাভাতে কোনও কার্যকর উপায় আছে?
গুগল করার সময়, আমি দেখতে পাচ্ছি যে ব্যবহারটি java.io.File#length()
ধীর হতে পারে।
পাশাপাশি পাওয়া যায় FileChannel
এমন একটি size()
পদ্ধতি রয়েছে ।
ফাইলের আকার পাওয়ার জন্য জাভাতে কোনও কার্যকর উপায় আছে?
উত্তর:
ঠিক আছে, আমি নীচের কোড দিয়ে এটি পরিমাপ করার চেষ্টা করেছি:
রান = 1 এবং পুনরাবৃত্তিগুলির জন্য = 1 টি ইউআরএল পদ্ধতি চ্যানেল দ্বারা সর্বাধিকবার অনুসরণ করা হয়। আমি প্রায় 10 বার কিছুটা বিরতি দিয়ে এটি চালাই। সুতরাং এক সময় অ্যাক্সেসের জন্য, ইউআরএলটি ব্যবহার করা আমার পক্ষে দ্রুততম মনে হতে পারে:
LENGTH sum: 10626, per Iteration: 10626.0
CHANNEL sum: 5535, per Iteration: 5535.0
URL sum: 660, per Iteration: 660.0
রান = 5 এবং পুনরাবৃত্তির জন্য = 50 চিত্রটি আলাদা আঁকবে।
LENGTH sum: 39496, per Iteration: 157.984
CHANNEL sum: 74261, per Iteration: 297.044
URL sum: 95534, per Iteration: 382.136
ফাইলগুলি অবশ্যই ফাইল সিস্টেমে কলগুলি ক্যাশে করছে, যখন চ্যানেল এবং ইউআরএল এর কিছু ওভারহেড রয়েছে।
কোড:
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;
}
}
stream.available()
ফাইলের দৈর্ঘ্য ফেরত দেয় না। এটি অন্যান্য স্ট্রিমগুলি অবরুদ্ধ না করে পড়ার জন্য উপলব্ধ বাইটের পরিমাণ ফেরত দেয়। এটি অবশ্যই ফাইলের দৈর্ঘ্যের সমান পরিমাণ বাইট নয়। একটি স্ট্রিম থেকে আসল দৈর্ঘ্য পেতে, আপনাকে সত্যই এটি পড়তে হবে (এবং এর মধ্যে পঠিত বাইটগুলি গণনা করুন)।
জিএইচডি প্রদত্ত মাপদণ্ডটি দৈর্ঘ্য পাওয়ার পাশাপাশি প্রচুর পরিমাণে অন্যান্য পদার্থের (যেমন প্রতিচ্ছবি, তাত্ক্ষণিক বস্তু ইত্যাদি) পরিমাপ করে। যদি আমরা এই বিষয়গুলি থেকে মুক্তি পাওয়ার চেষ্টা করি তবে একটি কলের জন্য আমি মাইক্রোসেকেন্ডে নিম্নলিখিত সময়গুলি পাই:
ফাইল যোগফল ___ 19.0, প্রতি আইট্রেশন ___ 19.0 রাফ সমষ্টি ___ 16.0, প্রতি আইট্রেট ___ 16.0 চ্যানেল যোগ ______737 প্রতি, প্রতি আইট্রেশন__273.0
100 রান এবং 10000 পুনরাবৃত্তির জন্য আমি পাই:
ফাইলের যোগফল__1767629.0, প্রতি ইটারেশন__17676290000000001 রাফ যোগফল ___ 881284.0, প্রতি ইটারেশন__0.8812840000000001 চ্যানেল যোগফল ___ 414286.0, প্রতি আইট্রেশন__0.414286
আমি যুক্তি হিসাবে 100MB ফাইলের নাম দিয়ে নিম্নলিখিত সংশোধিত কোডটি চালিয়েছি।
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));
}
}
}
এই পরীক্ষায় সমস্ত পরীক্ষার কেস ত্রুটিযুক্ত কারণ তারা পরীক্ষিত প্রতিটি পদ্ধতির জন্য একই ফাইল অ্যাক্সেস করে। সুতরাং ডিস্ক ক্যাচিং কিকস যা পরীক্ষাগুলি 2 এবং 3 থেকে উপকার করে। আমার বক্তব্য প্রমাণ করার জন্য আমি জিএইচএডি দ্বারা প্রদত্ত পরীক্ষার কেস নিয়েছি এবং গণনার ক্রম পরিবর্তন করেছি এবং নীচে ফলাফলগুলি রয়েছে।
ফলাফলের দিকে তাকিয়ে আমার মনে হয় ফাইল.লেন্থ () আসলেই বিজয়ী।
পরীক্ষার ক্রম হ'ল আউটপুট ক্রম। এমনকি আপনি আমার মেশিনে নেওয়া সময়টিকে মৃত্যুদণ্ড কার্যকর করার সময়ও দেখতে পারবেন কিন্তু ফাইল.লেন্থ () যখন প্রথম নয় এবং প্রথম ডিস্ক অ্যাক্সেস জিতেছে।
---
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
আমি যখন আপনার কোডটি সংস্থান পরিবর্তনের জন্য পরম পাথ দ্বারা অ্যাক্সেস করা কোনও ফাইল ব্যবহার করার জন্য পরিবর্তন করি, তখন আমি আলাদা ফলাফল পাই (1 রান, 1 পুনরাবৃত্তি এবং 100,000 বাইট ফাইলের জন্য - 10 বাইট ফাইলের জন্য সময় 100,000 বাইটের সমান হয়) )
দৈর্ঘ্য যোগফল: 33, প্রতি আইট্রেশন: 33.0
চ্যানেল যোগফল: প্রতি আইট্রেজ: 3626, 3626.0
ইউআরএল যোগ: 294, প্রতি আইট্রেশন: 294.0
আরগ্রিগের বেঞ্চমার্কের প্রতিক্রিয়া হিসাবে, ফাইলচ্যানেল ও র্যান্ডমএ্যাকসেসফিল ইনস্ট্যান্সগুলি খোলার / বন্ধ করার সময় গ্রহণ করা উচিত, কারণ এই ক্লাসগুলি ফাইলটি পড়ার জন্য একটি প্রবাহ খুলবে।
মানদণ্ডটি সংশোধন করার পরে, আমি 85MB ফাইলে 1 টি পুনরাবৃত্তির জন্য এই ফলাফলগুলি পেয়েছি:
file totalTime: 48000 (48 us)
raf totalTime: 261000 (261 us)
channel totalTime: 7020000 (7 ms)
একই ফাইলটিতে 10000 পুনরাবৃত্তির জন্য:
file totalTime: 80074000 (80 ms)
raf totalTime: 295417000 (295 ms)
channel totalTime: 368239000 (368 ms)
আপনার যা যা দরকার তা হ'ল ফাইলের আকার, ফাইল-দৈর্ঘ্য () এটি করার দ্রুততম উপায়। আপনি যদি ফাইলটি পড়া / লেখার মতো অন্যান্য উদ্দেশ্যে ফাইলটি ব্যবহার করার পরিকল্পনা করেন তবে আরএএফ আরও ভাল বাজি বলে মনে হয়। কেবল ফাইল সংযোগটি বন্ধ করতে ভুলবেন না :-)
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";
}
}
}
আমি এই একই ইস্যু মধ্যে দৌড়ে। আমার নেটওয়ার্ক শেয়ারে ফাইলের আকার এবং 90,000 ফাইলের সংশোধিত তারিখটি পাওয়া দরকার। জাভা ব্যবহার করা এবং যতটা সম্ভব ন্যূনতম হওয়াতে এটি খুব দীর্ঘ সময় নিতে পারে। (ফাইলটি থেকে আমার ইউআরএল এবং সেই সাথে অবজেক্টের পাথেরও দরকার ছিল So তাই এটি কিছুটা ভিন্ন, তবে এক ঘণ্টারও বেশি)) আমি তখন একটি স্থানীয় উইন 32 এক্সিকিউটেবল ব্যবহার করেছিলাম, এবং একই কাজটি করেছি, কেবল ফাইলটি ফেলে রেখেছি পাথ, সংশোধিত এবং কনসোলের আকার এবং জাভা থেকে এটি কার্যকর করা হয়েছে। গতি ছিল আশ্চর্যজনক। নেটিভ প্রক্রিয়া এবং ডেটা পড়তে আমার স্ট্রিং হ্যান্ডলিং এক সেকেন্ডে 1000 টিরও বেশি আইটেম প্রক্রিয়া করতে পারে।
সুতরাং নীচে লোকেরা উপরের মন্তব্যটিকে স্থান দিয়েছে, এটি একটি বৈধ সমাধান এবং আমার সমস্যাটি সমাধান করেছে। আমার ক্ষেত্রে আমি ফোল্ডারগুলি জানতাম আমার আগে সময়ের আকারের প্রয়োজন ছিল এবং আমি কমান্ড লাইনে আমার win32 অ্যাপ্লিকেশনটিতে যেতে পারি। আমি ঘন্টা থেকে কয়েক মিনিটের জন্য একটি ডিরেক্টরি প্রক্রিয়া করতে গিয়েছিলাম।
বিষয়টি উইন্ডোজ নির্দিষ্ট বলে মনে হয়েছিল। ওএস এক্স এর একই সমস্যা নেই এবং ওএস যত তাড়াতাড়ি করতে পারে তত দ্রুত নেটওয়ার্ক ফাইল তথ্য অ্যাক্সেস করতে পারে।
উইন্ডোজ জাভা ফাইল হ্যান্ডলিং ভয়ঙ্কর। ফাইলগুলির জন্য স্থানীয় ডিস্ক অ্যাক্সেস ঠিক আছে। এটি কেবল নেটওয়ার্ক শেয়ার যা ভয়াবহ পারফরম্যান্সের কারণ হয়েছিল। উইন্ডোজ নেটওয়ার্ক শেয়ারের তথ্য পেতে পারে এবং এক মিনিটের মধ্যেও মোট আকার গণনা করতে পারে।
--Ben
আপনি যদি কোনও ডিরেক্টরিতে একাধিক ফাইলের ফাইলের আকার চান তবে ব্যবহার করুন Files.walkFileTree
। আপনি BasicFileAttributes
যেটি পাবেন তা থেকে আপনি আকারটি পেতে পারেন।
এটি .length()
ফলাফলের উপর কল করা File.listFiles()
বা ফলাফলটি ব্যবহার Files.size()
করা তারপরে আরও দ্রুত Files.newDirectoryStream()
। আমার পরীক্ষার ক্ষেত্রে এটি প্রায় 100 গুণ দ্রুত ছিল।
Files.walkFileTree
অ্যান্ড্রয়েড 26+ এ উপলব্ধ।
আসলে, আমি "ls" দ্রুত হতে পারে বলে মনে করি। ফাইলের তথ্য পাওয়ার ক্ষেত্রে জাভাতে অবশ্যই কিছু সমস্যা রয়েছে। দুর্ভাগ্যক্রমে উইন্ডোজের জন্য পুনরাবৃত্ত ls এর সমতুল্য কোনও নিরাপদ পদ্ধতি নেই। (সেমিডি.এক্সির ডিআর / এস বিভ্রান্ত হতে পারে এবং অসীম লুপগুলিতে ত্রুটি উত্পন্ন করতে পারে)
এক্সপিতে, ল্যানে একটি সার্ভার অ্যাক্সেস করতে, একটি ফোল্ডারে ফাইলের গণনা (৩৩,০০০) এবং মোট আকার পেতে উইন্ডোতে আমার 5 সেকেন্ড সময় লাগে।
আমি যখন জাভাতে এর মাধ্যমে পুনরাবৃত্তি করি তখন এটি আমার 5 মিনিটের বেশি সময় নেয়। ফাইল.লেন্থ (), file.lastModified (), এবং file.toURI () করতে যে সময় লাগে তা আমি পরিমাপ করতে শুরু করেছিলাম এবং যা আমি পেয়েছি তা হল যে আমার 99% সময় এই 3 কল দ্বারা নেওয়া হয়। 3 টি কল আমার আসলে করা দরকার ...
1000 ফাইলের জন্য পার্থক্যটি হ'ল সার্ভারে 1800 মিমি এর তুলনায় 15 মিমি স্থানীয়। জাভার সার্ভার পাথ স্ক্যানিং হাস্যকরভাবে ধীর। যদি সেই একই ফোল্ডারটি স্ক্যান করতে নেটিভ ওএস দ্রুত হতে পারে তবে জাভা কেন পারবে না?
আরও সম্পূর্ণ পরীক্ষা হিসাবে, আমি স্থানীয়ভাবে ফাইলগুলির বিপরীতে সার্ভারে থাকা ফাইলগুলির আকার এবং পরিবর্তিত তারিখের তুলনায় এক্সপিতে ওয়াইনমার্জ ব্যবহার করেছি। এটি প্রতিটি ফোল্ডারে 33,000 ফাইলের সম্পূর্ণ ডিরেক্টরি ট্রিতে পুনরাবৃত্তি করছিল। মোট সময়, 7 সেকেন্ড। জাভা: 5 মিনিটের বেশি।
সুতরাং ওপি থেকে মূল বিবৃতি এবং প্রশ্নটি সত্য এবং বৈধ। স্থানীয় ফাইল সিস্টেমের সাথে কাজ করার সময় এটি কম লক্ষণীয়। 33,000 আইটেমের সাথে ফোল্ডারের স্থানীয় তুলনা করতে উইনমার্জে 3 সেকেন্ড সময় লাগে এবং জাভাতে স্থানীয়ভাবে 32 সেকেন্ড লাগে। সুতরাং আবার, জাভা বনাম নেটিভ এই প্রাথমিক পরীক্ষাগুলিতে 10x ধীর গতি।
জাভা ১.6.০.২২ (সর্বশেষ), গিগাবিট ল্যান এবং নেটওয়ার্ক সংযোগগুলি, পিং 1 এমএসের চেয়ে কম (একই স্যুইচে উভয়)
জাভা ধীর।
জিএইএডির মানদণ্ড থেকে লোকেরা কয়েকটি বিষয় উল্লেখ করেছে:
1> বালাসসির মতোই উল্লেখ করা হয়েছে: এই ক্ষেত্রে প্রবাহিত ailable উপলব্ধ)
কারণ উপলব্ধ () একটি অনুমান দেয় এই ইনপুট স্ট্রিমের জন্য কোনও পদ্ধতির পরবর্তী অনুরোধ দ্বারা অবরুদ্ধ না করে এই ইনপুট স্ট্রিম থেকে বাইটের সংখ্যা (বা পড়া দেয়।
সুতরাং 1 টি ইউআরএল অপসারণ এই পদ্ধতির।
2> স্টুয়ার্টএইচ হিসাবে উল্লেখ করা হয়েছে - পরীক্ষা চালানোর ক্রমটিও ক্যাশে পার্থক্য তৈরি করে, তাই পরীক্ষাটি আলাদাভাবে চালিয়ে বের করে নিন।
এখন পরীক্ষা শুরু করুন:
যখন চ্যানেল একা একা চলে:
CHANNEL sum: 59691, per Iteration: 238.764
যখন LENGTH একা একা চলে:
LENGTH sum: 48268, per Iteration: 193.072
সুতরাং মনে হচ্ছে লেংথটি এখানে বিজয়ী:
@Override
public long getResult() throws Exception {
File me = new File(FileSizeBench.class.getResource(
"FileSizeBench.class").getFile());
return me.length();
}