কোনও ইনপুট স্ট্রিম থেকে দক্ষতার সাথে অ্যান্ড্রয়েড পঠন


152

আমি তৈরি করছি এমন একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশনটির জন্য আমি কোনও ওয়েবসাইটে একটি এইচটিটিপি অনুরোধ করছি।

আমি একটি ডিফল্ট HTTPClient ব্যবহার করছি এবং অনুরোধ জারির জন্য এইচটিটিপিগেট ব্যবহার করছি। আমি সত্তার প্রতিক্রিয়া পেয়েছি এবং এ থেকে পৃষ্ঠার এইচটিএমএল পাওয়ার জন্য একটি ইনপুট স্ট্রিম অবজেক্ট পেয়েছি।

আমি তারপরে উত্তরটি দিয়ে চক্রটি নিম্নলিখিতভাবে করছি:

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";

while(x!= null){
total += x;
x = r.readLine();
}

তবে এটি ভয়ানকভাবে ধীর।

এটি কি অদক্ষ? আমি একটি বড় ওয়েব পৃষ্ঠা লোড করছি না - www.cokezone.co.uk তাই ফাইলের আকারটি বড় নয়। এই কাজ করতে একটি ভাল উপায় আছে কি?

ধন্যবাদ

অ্যান্ডি


আপনি যদি লাইনগুলিকে প্রকৃতপক্ষে পার্স না করেন তবে লাইন লাইনে পড়তে এটি প্রচুর অর্থবোধ করে না। আমি বরং স্থির আকারের বাফারের মাধ্যমে চরটি
মাইক 76

উত্তর:


355

আপনার কোডের সমস্যাটি হ'ল এটি প্রচুর ভারী Stringঅবজেক্ট তৈরি করে, সেগুলির বিষয়বস্তু অনুলিপি করে এবং সেগুলিতে অপারেশন করে। পরিবর্তে, প্রতিটি সংযোজনে StringBuilderনতুন Stringঅবজেক্ট তৈরি করা এবং চর অ্যারে অনুলিপি এড়ানোর জন্য আপনার ব্যবহার করা উচিত । আপনার মামলার বাস্তবায়ন এই জাতীয় কিছু হবে:

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
    total.append(line).append('\n');
}

আপনি এখন totalএটিকে রূপান্তর না করেই ব্যবহার করতে পারেন Stringতবে ফলাফল হিসাবে যদি আপনার প্রয়োজন হয় Stringতবে কেবল যোগ করুন:

স্ট্রিং রেজাল্ট = টোটাল.টোস্ট্রিং ();

আমি আরও ভাল করে ব্যাখ্যা করার চেষ্টা করব ...

  • a += b(বা a = a + b), যেখানে aএবং bস্ট্রিংগুলি উভয়ের সামগ্রীর অনুলিপি করে a এবং b একটি নতুন অবজেক্টে (নোট করুন যে আপনিও অনুলিপি করছেন a, যার মধ্যে জমা রয়েছে String), এবং প্রতিটি অনুলিপিতে আপনি সেই অনুলিপিগুলি করছেন।
  • a.append(b)যেখানে aএকটি StringBuilder, সরাসরি সামগ্রীতে সংযোজন করা bহয় a, তাই আপনি প্রতিটি পুনরাবৃত্তিতে জমা হওয়া স্ট্রিংটি অনুলিপি করেন না।

23
বোনাস পয়েন্টগুলির জন্য, স্ট্রিংবিল্ডার ভরাট হিসাবে পুনরায় স্থানগুলি এড়ানোর জন্য একটি প্রাথমিক ক্ষমতা সরবরাহ করুন: StringBuilder total = new StringBuilder(inputStream.available());
ডক্কাবি

10
এটি কি নতুন লাইনের চরিত্রগুলি কেটে দেয় না?
নাথান শোয়ারম্যান

5
এইভাবে চেষ্টা / ক্যাপচারের সময়টি মুড়ে ফেলতে ভুলবেন না: চেষ্টা করুন {जबकि ((লাইন = r.readLine ())! = নাল) {total.append (লাইন); }} ক্যাচ (আইওএক্সেপশন ই) {লগ.আই (ট্যাগ, "ইনপুটস্ট্রিমটোস্ট্রিং ফাংশনে রিডলাইন নিয়ে সমস্যা"); }
বটবট

4
@ বটবট: লগ করা এবং কোনও ব্যতিক্রম উপেক্ষা করা কেবল ব্যতিক্রম উপেক্ষা করার চেয়ে বেশি ভাল নয় ...
মাত্তি ভির্ককুনেন

50
এটি আশ্চর্যজনক যে অ্যান্ড্রয়েডের অন্তর্নির্মিত স্ট্রিম থেকে স্ট্রিং রূপান্তর নেই। গ্রহে ওয়েবে এবং অ্যাপে প্রতিটি কোড স্নিপেট থাকা একটি readlineলুপটিকে পুনরায় বাস্তবায়িত করা হাস্যকর। সেই প্যাটার্নটি 70 এর দশকে মটর সবুজ দিয়ে মারা উচিত ছিল।
এডওয়ার্ড বেরি

35

একটি স্ট্রিমকে স্ট্রিতে রূপান্তর করতে আপনি কি বিল্ট ইন পদ্ধতি ব্যবহার করেছেন? এটি অ্যাপাচি কমন্স লাইব্রেরির অংশ (org.apache.commons.io.IOUtils)।

তাহলে আপনার কোডটি এই এক লাইনে থাকবে:

String total = IOUtils.toString(inputStream);

এটির জন্য ডকুমেন্টেশন এখানে পাওয়া যাবে: http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29

অ্যাপাচি কমন্স আইও গ্রন্থাগারটি এখান থেকে ডাউনলোড করা যেতে পারে: http://commons.apache.org/io/download_io.cgi


আমি বুঝতে পারি এটি একটি দেরিতে প্রতিক্রিয়া, তবে এখনই গুগল অনুসন্ধানের মাধ্যমে এটিকে হোঁচট খাওয়ার ঘটনা ঘটেছে।
মাকোটোসান

61
অ্যান্ড্রয়েড এপিআইতে আইওউটিস অন্তর্ভুক্ত নেই
চার্লস মা

2
ডান, যে কারণে আমি এটি আছে যে বাইরের গ্রন্থাগার উল্লেখ। আমি আমার অ্যান্ড্রয়েড প্রকল্পে লাইব্রেরি যুক্ত করেছি এবং এটি স্ট্রিম থেকে পড়া সহজ করে তুলেছে।
মাকোটোসান

আমি এটি কোথায় ডাউনলোড করতে পারি এবং আপনি কীভাবে এটি আপনার অ্যান্ড্রয়েড প্রকল্পে আমদানি করলেন?
সাফারি

3
আপনার যদি এটি ডাউনলোড করতে হয় তবে আমি এটিকে "বিল্ট ইন" বলব না; তবুও, আমি কেবল এটি ডাউনলোড করেছি, এবং এটি দিয়ে যাব।
বি ক্লে শ্যানন

15

পেয়ারার সাথে আরেকটি সম্ভাবনা:

নির্ভরতা: compile 'com.google.guava:guava:11.0.2'

import com.google.common.io.ByteStreams;
...

String total = new String(ByteStreams.toByteArray(inputStream ));

9

আমি বিশ্বাস করি এটি যথেষ্ট দক্ষ ... একটি ইনপুটস্ট্রিম থেকে স্ট্রিং পেতে, আমি নিম্নলিখিত পদ্ধতিটি কল করব:

public static String getStringFromInputStream(InputStream stream) throws IOException
{
    int n = 0;
    char[] buffer = new char[1024 * 4];
    InputStreamReader reader = new InputStreamReader(stream, "UTF8");
    StringWriter writer = new StringWriter();
    while (-1 != (n = reader.read(buffer))) writer.write(buffer, 0, n);
    return writer.toString();
}

আমি সর্বদা ইউটিএফ -8 ব্যবহার করি। আপনি অবশ্যই ইনপুট স্ট্রিমের পাশাপাশি একটি আর্গুমেন্ট হিসাবে চরসেট সেট করতে পারেন।


6

এই সম্পর্কে কি. আরও ভাল পারফরম্যান্স দেবে বলে মনে হচ্ছে।

byte[] bytes = new byte[1000];

StringBuilder x = new StringBuilder();

int numRead = 0;
while ((numRead = is.read(bytes)) >= 0) {
    x.append(new String(bytes, 0, numRead));
}

সম্পাদনা: আসলে এই ধরণের স্টিলবাইট এবং মরিস পেরির উভয়ই অন্তর্ভুক্ত


সমস্যাটি হ'ল - আমি শুরু করার আগে যে জিনিসটি পড়ছি তার আকারটি আমি জানি না - তাই বাড়তে থাকা অ্যারেগুলির কিছু ফর্মের প্রয়োজন হতে পারে। বাইট অ্যারের আকারটি অপ্টিমাইজ করার জন্য im পুনরুদ্ধার করা জিনিসটি কত বড় is মোবাইল ডিভাইসে এটির মতো দক্ষ হতে হবে যা মূল সমস্যা! তবে এই ধারণার জন্য ধন্যবাদ - আজ রাতে এটিকে একটি শট দেবে এবং আপনাকে জানাবে যে পারফরম্যান্স লাভের ক্ষেত্রে এটি কীভাবে পরিচালনা করে!
রেনেগাদেআন্দি

আগত প্রবাহের আকারটি এটি গুরুত্বপূর্ণ বলে আমি মনে করি না। উপরের কোডটি একবারে 1000 বাইট পড়ে তবে আপনি সেই আকারটি বাড়াতে / হ্রাস করতে পারবেন। আমার পরীক্ষার সাথে এটি এতটা তফাত আবহাওয়া তৈরি করতে পারেনি যা আমি 1000/10000 বাইট ব্যবহার করেছি। যদিও এটি ছিল একটি সাধারণ জাভা অ্যাপ্লিকেশন। এটি একটি মোবাইল ডিভাইসে আরও গুরুত্বপূর্ণ হতে পারে।
অ্যাড্রিয়ান

4
আপনি একটি ইউনিকোড সত্তা শেষ করতে পারেন যা পরবর্তী দুটি পাঠে কাটা হয়েছে। কোনও ধরণের সীমানা চরিত্র না হওয়া পর্যন্ত পড়া ভাল \ n, যা ঠিক ততটাই বাফারড্রেডার করে।
জ্যাকব নর্ডফালক

4

জাইম সোরিয়ানোর উত্তরের চেয়ে সম্ভবত কিছুটা দ্রুত এবং অ্যাড্রিয়ানের উত্তরের মাল্টি-বাইট এনকোডিং সমস্যা ছাড়াই আমি পরামর্শ দিই:

File file = new File("/tmp/myfile");
try {
    FileInputStream stream = new FileInputStream(file);

    int count;
    byte[] buffer = new byte[1024];
    ByteArrayOutputStream byteStream =
        new ByteArrayOutputStream(stream.available());

    while (true) {
        count = stream.read(buffer);
        if (count <= 0)
            break;
        byteStream.write(buffer, 0, count);
    }

    String string = byteStream.toString();
    System.out.format("%d bytes: \"%s\"%n", string.length(), string);
} catch (IOException e) {
    e.printStackTrace();
}

এটি দ্রুত হবে কেন আপনি ব্যাখ্যা করতে পারেন?
আখিল বাবা

এটি নতুন লাইন অক্ষরের জন্য ইনপুট স্ক্যান করে না, তবে কেবল 1024 বাইটের খণ্ডগুলি পড়ে। আমি বিতর্ক করছি না এটি কোনও ব্যবহারিক পার্থক্য তৈরি করবে।
হেইনার

@ রোনাল্ড উত্তর সম্পর্কে কোন মন্তব্য? তিনি একই কাজ করছেন তবে ইনপুটস্ট্রিম আকারের সমান বৃহত্তর অংশের জন্য। এছাড়াও আমি নিকোলা উত্তর হিসাবে বাইট অ্যারের চেয়ে চর অ্যারে স্ক্যান করলে এটি কতটা আলাদা? আসলে আমি কেবল জানতে চেয়েছিলাম কোন ক্ষেত্রে কোন পদ্ধতির সবচেয়ে ভাল? এছাড়াও পঠনলাইন \ n এবং \ r মুছে ফেলেছে তবে আমি এমনকি গুগল আইও অ্যাপ্লিকেশন কোডও দেখেছি তারা রিডলাইন ব্যবহার করছে
আখিল বাবা

3

সম্ভবত তারপরে 'একবারে একটি লাইন' পড়ুন এবং স্ট্রিংগুলিতে যোগ দিন, 'সমস্ত উপলব্ধ পড়া' চেষ্টা করুন যাতে লাইনের শেষের জন্য স্ক্যানিং এড়ানোর জন্য, এবং স্ট্রিংয়ের সাথে যোগ দেয় না।

যেমন, InputStream.available()এবংInputStream.read(byte[] b), int offset, int length)


হুম। সুতরাং এটি এর মতো হবে: int অফসেট = 5000; বাইট [] বিআরআর = নতুন বাইট [100]; বাইট [] মোট = বাইট [5000]; যখন (ইনপুটস্ট্রিম.ভ্যাভলভেট) {অফসেট = ইনপুটস্ট্রিম.ড্রেড (বিআরআর, অফসেট, 100); (int i = 0; i <অফসেট; i ++) {মোট [i] = বিআরআর [i]; A bArr = নতুন বাইট [100]; That আসলেই কি এটি আরও দক্ষ - বা আমি এটি খারাপভাবে লিখেছি! একটি উদাহরণ দিন!
রেনেগডএন্ডে

2
না, না, না, আমি সহজেই বলতে চাইছি {বাইট মোট [] = নতুন [instrm.available ()]; instrm.read (মোট, 0, total.length); } এবং এর পরে যদি আপনার এটি স্ট্রিং হিসাবে প্রয়োজন হয় তবে {স্ট্রিং asString = স্ট্রিং (মোট, 0, মোট. দৈর্ঘ্য, "utf-8") ব্যবহার করুন; // ধরে নিন utf8 :-)}
স্টিলবাইটস

2

একসাথে এক লাইনের পাঠ্য পড়া এবং পৃথকভাবে স্ট্রিংয়ের সাথে সংযুক্ত লাইনের সংযোজন হ'ল প্রতিটি লাইন এবং এতগুলি পদ্ধতির অনুরোধগুলির ওভারহেড নিষ্কাশন করতে উভয়ই সময় সাপেক্ষ।

আমি স্ট্রিম ডেটা ধরে রাখতে একটি শালীন আকারের বাইট অ্যারে বরাদ্দ করে আরও ভাল পারফরম্যান্স পেতে সক্ষম হয়েছি এবং যা প্রয়োজন অনুসারে বড় আকারের অ্যারের সাথে পুনরাবৃত্তভাবে প্রতিস্থাপন করা হয়েছে এবং অ্যারেটি যতটা রাখতে পারে তা পড়ার চেষ্টা করে।

কোনও কারণে, কোডটি HTTPUrlConnication দ্বারা ফেরত কোডটি যখন ইনপুটস্ট্রিম ব্যবহার করেছিল তখন অ্যান্ড্রয়েড বারবার পুরো ফাইলটি ডাউনলোড করতে ব্যর্থ হয়েছিল, তাই আমি পুরো ফাইলটি পেতে পারি বা বাতিল করতে পারি তা নিশ্চিত করতে আমাকে একটি বাফার্ডারিডার এবং হ্যান্ড-রোলড টাইমআউট প্রক্রিয়া উভয়ই ব্যবহার করতে হয়েছিল ensure ট্রান্সফার.

private static  final   int         kBufferExpansionSize        = 32 * 1024;
private static  final   int         kBufferInitialSize          = kBufferExpansionSize;
private static  final   int         kMillisecondsFactor         = 1000;
private static  final   int         kNetworkActionPeriod        = 12 * kMillisecondsFactor;

private String loadContentsOfReader(Reader aReader)
{
    BufferedReader  br = null;
    char[]          array = new char[kBufferInitialSize];
    int             bytesRead;
    int             totalLength = 0;
    String          resourceContent = "";
    long            stopTime;
    long            nowTime;

    try
    {
        br = new BufferedReader(aReader);

        nowTime = System.nanoTime();
        stopTime = nowTime + ((long)kNetworkActionPeriod * kMillisecondsFactor * kMillisecondsFactor);
        while(((bytesRead = br.read(array, totalLength, array.length - totalLength)) != -1)
        && (nowTime < stopTime))
        {
            totalLength += bytesRead;
            if(totalLength == array.length)
                array = Arrays.copyOf(array, array.length + kBufferExpansionSize);
            nowTime = System.nanoTime();
        }

        if(bytesRead == -1)
            resourceContent = new String(array, 0, totalLength);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }

    try
    {
        if(br != null)
            br.close();
    }
    catch(IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

সম্পাদনা: দেখা যাচ্ছে যে আপনার যদি সামগ্রীটি পুনরায় এনকোড করার প্রয়োজন না হয় (যেমন, আপনি সামগ্রীটি AS হিসাবে চান ) আপনার কোনও পাঠক সাবক্ল্যাস ব্যবহার করা উচিত নয়। উপযুক্ত স্ট্রিম সাবক্লাসটি কেবল ব্যবহার করুন।

অতিরিক্ত 2 থেকে 3 বার গতি বাড়ানোর জন্য পূর্বের পদ্ধতির শুরুটি নীচের সাথে সম্পর্কিত লাইনের সাথে প্রতিস্থাপন করুন ।

String  loadContentsFromStream(Stream aStream)
{
    BufferedInputStream br = null;
    byte[]              array;
    int                 bytesRead;
    int                 totalLength = 0;
    String              resourceContent;
    long                stopTime;
    long                nowTime;

    resourceContent = "";
    try
    {
        br = new BufferedInputStream(aStream);
        array = new byte[kBufferInitialSize];

এটি উপরোক্ত এবং স্বীকৃত উত্তরের চেয়ে অনেক দ্রুত। আপনি কীভাবে অ্যান্ড্রয়েডে "রিডার" এবং "স্ট্রিম" ব্যবহার করবেন?
স্টিভজিএসডি

1

যদি ফাইলটি দীর্ঘ হয় তবে আপনি প্রতিটি লাইনের জন্য স্ট্রিং কনটেনটেশন ব্যবহার না করে স্ট্রিংবিল্ডারে যুক্ত হয়ে আপনার কোডটি অনুকূল করতে পারেন।


এটি সত্যিকারের হতে এত দীর্ঘ নয় - এটি ওয়েবসাইটের www.cokezone.co.uk পৃষ্ঠার উত্স - এত বড় নয়। অবশ্যই 100kb এর চেয়ে কম।
রেনেগাদেআন্ডি

কীভাবে এটিকে আরও দক্ষ করা যায় - বা এটি এমনকি যদি অকার্যকর হয় তবে কারও কি অন্য কোনও ধারণা আছে? যদি দ্বিতীয়টি সত্য হয় - তবে এটি এত বেশি সময় নেয় কেন? আমি বিশ্বাস করি না যে সংযোগটি দোষের জন্য।
রেনেগাদেআন্ডি

1
    byte[] buffer = new byte[1024];  // buffer store for the stream
    int bytes; // bytes returned from read()

    // Keep listening to the InputStream until an exception occurs
    while (true) {
        try {
            // Read from the InputStream
            bytes = mmInStream.read(buffer);

            String TOKEN_ = new String(buffer, "UTF-8");

            String xx = TOKEN_.substring(0, bytes);

1

ইনপুট স্ট্রিমটিকে স্ট্রিংয়ে রূপান্তর করতে আমরা বাফারড্রিডার.ড্রেডলাইন () পদ্ধতিটি ব্যবহার করি । আমরা বাফারড্রেডার শূন্য না হওয়া পর্যন্ত পুনরাবৃত্তি করি যার অর্থ পড়ার জন্য আর কোনও ডেটা নেই। প্রতিটি লাইন একটি স্ট্রিংবিল্ডারে যুক্ত হবে এবং স্ট্রিং হিসাবে ফিরে আসবে।

 public static String convertStreamToString(InputStream is) {

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}`

এবং অবশেষে যে কোনও ক্লাস থেকে যেখানে আপনি ফাংশন কলটি রূপান্তর করতে চান

String dataString = Utils.convertStreamToString(in);

সম্পূর্ণ


-1

আমি সম্পূর্ণ ডেটা পড়তে ব্যবহার করছি:

// inputStream is one instance InputStream
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
String dataString = new String(data);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.