سؤال

ما هي طريقة فعالة من تقسيم السلسلة إلى قطع من 1024 بايت في جافا ؟ إذا كان هناك أكثر من قطعة واحدة ثم رأس(حجم ثابت سلسلة) يجب أن تتكرر في جميع اللاحقة قطع.

هل كانت مفيدة؟

المحلول

وسلاسل وبايت هما شيئان مختلفان تماما، لذلك يريدون تقسيم سلسلة إلى بايت لا معنى له كما يريدون تقسيم اللوحة إلى الآيات.

ما الذي كنت فعلا تريد أن تفعل؟

لتحويل بين السلاسل وبايت، تحتاج إلى تحديد الترميز الذي يمكن ترميز كل الأحرف في سلسلة. اعتمادا على الترميز والشخصيات، بعضها قد تمتد أكثر من بايت واحد.

ويمكنك إما تقسيم سلسلة إلى قطع من 1024 حرفا وترميز تلك كما بايت، ولكن بعد كل قطعة قد يكون أكثر من 1024 بايت.

وأو يمكنك ترميز السلسلة الأصلية إلى بايت ومن ثم تقسيمها إلى أجزاء من 1024، ولكن بعد ذلك لديك للتأكد من إلحاق لهم كما بايت قبل فك كلها إلى سلسلة مرة أخرى، أو قد تحصل أحرف مشوشة في نقطة الانقسام عندما يمتد أكثر من حرف 1 بايت.

إذا كنت قلقة بشأن استخدام الذاكرة عندما سلسلة يمكن أن تكون طويلة جدا، يجب عليك استخدام تيارات (حزمة java.io) إلى لEN / فك التشفير وتقسيم، وذلك لتجنب حفظ البيانات في الذاكرة عدة مرات كما نسخة. من الناحية المثالية، يجب تجنب وجود سلسلة الأصلي في قطعة واحدة على الإطلاق، وبدلا من استخدام الجداول لقراءتها في قطع صغيرة من أي مكان يمكنك الحصول عليه من.

نصائح أخرى

لديك اثنين من الطرق السريعة و الذاكرة طريقة المحافظة.ولكن أولا عليك أن تعرف ما هي الشخصيات في السلسلة.ASCII?هل هناك علامات تغير في الصوت (الأحرف بين 128 و 255) أو حتى Unicode (s.getChar() بإرجاع شيء > 256).اعتمادا على ذلك ، سوف تحتاج إلى استخدام ترميز مختلفة.إذا كان لديك البيانات الثنائية ، في محاولة "iso-8859-1" لأنه سوف الحفاظ على البيانات في السلسلة.إذا كان لديك Unicode محاولة "utf-8".سأفترض البيانات الثنائية:

String encoding = "iso-8859-1";

أسرع طريقة:

ByteArrayInputStream in = new ByteArrayInputStream (string.getBytes(encoding));

علما أن سلسلة Unicode ، لذلك كل حرف يحتاج اثنين بايت.سيكون لديك لتحديد ترميز (لا تعتمد على "منصة الافتراضية".هذا سوف يسبب الألم في وقت لاحق).

الآن يمكنك أن تقرأ في 1024 قطع باستخدام

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) { ... }

هذا يحتاج إلى حوالي ثلاثة أضعاف ذاكرة الوصول العشوائي سلسلة الأصلي.

المزيد من الذاكرة المحافظة طريقة هي كتابة المحول الذي يأخذ StringReader و OutputStreamWriter (الذي يلف ByteArrayOutputStream).نسخ بايت من القارئ إلى الكاتب حتى الكامنة المخزن المؤقت الذي يحتوي على قطعة واحدة من البيانات:

عندما تفعل ذلك, نسخ البيانات إلى الناتج الحقيقي (يتبع رأس) ، نسخ إضافية بايت (التي Unicode->بايت التحويل قد ولدت) إلى درجة الحرارة العازلة اتصل العازلة.إعادة تعيين() وأكتب temp المخزن إلى المخزن المؤقت.

رمز يشبه هذا (لم تختبر):

StringReader r = new StringReader (string);
ByteArrayOutputStream buffer = new ByteArrayOutputStream (1024*2); // Twice as large as necessary
OutputStreamWriter w = new OutputStreamWriter  (buffer, encoding);

char[] cbuf = new char[100];
byte[] tempBuf;
int len;
while ((len = r.read(cbuf, 0, cbuf.length)) > 0) {
    w.write(cbuf, 0, len);
    w.flush();
    if (buffer.size()) >= 1024) {
        tempBuf = buffer.toByteArray();
        ... ready to process one chunk ...
        buffer.reset();
        if (tempBuf.length > 1024) {
            buffer.write(tempBuf, 1024, tempBuf.length - 1024);
        }
    }
}
... check if some data is left in buffer and process that, too ...

هذا يحتاج سوى بضع كيلو بايت من ذاكرة الوصول العشوائي.

[تحرير] كان هناك نقاش مستفيض حول البيانات الثنائية في السلاسل في التعليقات.أولا وقبل كل شيء, انها آمنة تماما لوضع البيانات الثنائية إلى سلسلة طالما كنت حذرا عندما خلق له وتخزينه في مكان ما.لخلق مثل هذه السلسلة ، واتخاذ byte[] مجموعة:

String safe = new String (array, "iso-8859-1");

في جافا, ISO-8859-1 (a.ك.ISO-Latin1) هو 1:1 رسم الخرائط.هذا يعني بايت في مجموعة لا تفسر بأي شكل من الأشكال.الآن يمكنك استخدام substring() وما شابه ذلك على البيانات أو البحث مع مؤشر تشغيل regexp على ذلك ، إلخ.على سبيل المثال تجد موقف من 0 بايت:

int pos = safe.indexOf('\u0000');

وهذا مفيد خصوصا إذا كنت لا تعرف ترميز البيانات و تريد أن يكون لها نظرة على ذلك من قبل بعض الترميز يعبث معها.

كتابة البيانات في مكان ما ، عكس العملية:

byte[] data = آمنة.getBytes("iso-8859-1");

أبدا استخدام الطرق الافتراضية new String(array) أو String.getBytes()! يوم الرمز سوف يتم تنفيذها على منصة مختلفة و سوف كسر.

المشكلة الآن من الشخصيات > 255 في السلسلة.إذا كنت تستخدم هذا الأسلوب لن يكون من أي وقت مضى أي حرف في سلاسل الخاص بك.وقال إذا كانت هناك أي لسبب ما ، ثم getBytes() رمي استثناء لأنه لا يوجد طريقة للتعبير عن جميع أحرف Unicode في ISO-Latin1, لذلك كنت آمنة بمعنى أن القانون لن تفشل بصمت.

قد يجادل البعض بأن هذه ليست آمنة بما فيه الكفاية ويجب أن لا تخلط بايت السلسلة.في هذا اليوم عصر نحن لا نملك هذا الترف.الكثير من البيانات لديه صريحة ترميز المعلومات (الملفات ، على سبيل المثال ، لم يكن لديك "ترميز" السمة في نفس الطريقة كما لديهم أذونات الوصول أو اسم).XML هي واحدة من عدد قليل من الأشكال التي قد صريحة ترميز المعلومات وهناك المحررين مثل Emacs أو jEdit التي تستخدم التعليقات على تحديد هذه المعلومات الحيوية.وهذا يعني أنه عند معالجة تيارات بايت, يجب أن تعرف دائما في ترميز هم.اعتبارا من الآن, ليس من الممكن كتابة التعليمات البرمجية التي سوف تعمل دائما ، بغض النظر عن مصدر البيانات.

حتى مع XML ، يجب قراءة رأس ملف بايت لتحديد ترميز قبل أن تتمكن من فك اللحوم.

النقطة المهمة هي أن تجلس و معرفة الترميز المستخدمة في توليد دفق البيانات لديك إلى عملية.إذا كنت تفعل ذلك, أنت جيد, إذا كنت لا, أنت محكوم.الارتباك تنبع من حقيقة أن معظم الناس لا يدركون أن نفس بايت يمكن أن تعني أشياء مختلفة اعتمادا على ترميز أو حتى أن هناك أكثر من الترميز.كما أنه من شأنه أن يساعد إذا الشمس لم أدخل مفهوم "منصة الترميز الافتراضي."

نقاط هامة للمبتدئين:

  • هناك أكثر من ترميز (محارف).
  • هناك المزيد من الشخصيات من اللغة الإنجليزية يستخدم.بل هناك عدة مجموعات من الأرقام (ASCII, العرض الكامل, العربية-الهندية, بنغالي).
  • يجب أن تعرف أي ترميز كان يستخدم لتوليد البيانات التي يتم معالجتها.
  • يجب أن تعرف أي ترميز يجب أن تستخدم لكتابة البيانات التي يتم معالجتها.
  • يجب أن تعرف الطريقة الصحيحة لتحديد هذا الترميز معلومات البرنامج التالي يمكن فك الإخراج الخاص بك (XML رأس HTML meta الخاصة ترميز تعليق أيا كان).

أيام ASCII أكثر.

وأنا أعلم أنا في وقت متأخر، ولكن كنت أبحث عن حل نفسي وجدت جوابي بعد ذلك أفضل إجابة:

private static String chunk_split(String original, int length, String separator) throws IOException {
    ByteArrayInputStream bis = new ByteArrayInputStream(original.getBytes());
    int n = 0;
    byte[] buffer = new byte[length];
    String result = "";
    while ((n = bis.read(buffer)) > 0) {
        for (byte b : buffer) {
            result += (char) b;
        }
        Arrays.fill(buffer, (byte) 0);
        result += separator;
    }
    return result;
}

على مثال : في

public static void main(String[] args) throws IOException{
       String original = "abcdefghijklmnopqrstuvwxyz";
       System.out.println(chunk_split(original,5,"\n"));
}

<القوي> ناتج : ل

abced
fghij
klmno
pqrst
uvwxy
z

وكنت أحاول هذا لنفسي، ولست بحاجة إلى قطعة سلسلة ضخمة (ما يقرب من 10 MB) بنسبة 1 MB. وهذا يساعد على قطعة البيانات في الحد الأدنى من الوقت. (أقل من ثانية).

private static ArrayList<String> chunkLogMessage(String logMessage) throws Exception {
    ArrayList<String> messages = new ArrayList<>();
    if(logMessage.getBytes().length > CHUNK_SIZE) {
        Log.e("chunk_started", System.currentTimeMillis()+"");
        byte[] buffer = new byte[CHUNK_SIZE];
        int start = 0, end = buffer.length;
        long remaining = logMessage.getBytes().length;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(logMessage.getBytes());
        while ((inputStream.read(buffer, start, end)) != -1){
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            outputStream.write(buffer, start, end);
            messages.add(outputStream.toString("UTF-8"));
            remaining = remaining - end;
            if(remaining <= end){
                end = (int) remaining;
            }
        }
        Log.e("chunk_ended", System.currentTimeMillis()+"");
        return messages;
    }
    messages.add(logMessage);
    return messages;
}

وLogcat:

22:08:00.262 3382-3425/com.sample.app E/chunk_started: 1533910080261
22:08:01.228 3382-3425/com.sample.app E/chunk_ended: 1533910081228
22:08:02.468 3382-3425/com.sample.app E/chunk_started: 1533910082468
22:08:03.478 3382-3425/com.sample.app E/chunk_ended: 1533910083478
22:09:19.801 3382-3382/com.sample.app E/chunk_started: 1533910159801
22:09:20.662 3382-3382/com.sample.app E/chunk_ended: 1533910160662

نعم، معظم إن لم يكن كل ما سبق ستعمل بالتأكيد.

وأو هل يمكن أن تحقق من هذا المشروع الذي يفعل ذلك بالضبط. إلا أنها قادرة على قطعة سلاسل ليس فقط، ولكن أيضا البايت المصفوفات، inputstreams والملفات.

ولديها 2 فئات هي: DataChunker وStringChunker


DataChunker chunker = new DataChunker(8192, blob) {
@Override 
public void chunkFound(byte[] foundChunk, int bytesProcessed) {
//process chunk here
}
@Override 
public void chunksExhausted(int bytesProcessed) { 
//called when all the blocks have been exhausted
} 
};

String blob = "Experience is wasted if history does not repeat itself...Gbemiro Jiboye";

 final StringBuilder builder = new StringBuilder();
        StringChunker chunker = new StringChunker(4, blob) {
            @Override
            public void chunkFound(String foundChunk, int bytesProcessed) {
                builder.append(foundChunk);
                System.out.println("Found: "+foundChunk+", bytesProcessed: "+bytesProcessed+" bytes");
            }

            @Override
            public void chunksExhausted(int bytesProcessed) {
                System.out.println("Processed all of: "+bytesProcessed+" bytes. Rebuilt string is: "+builder.toString());
            }
        };

ووblob في منشئ منشئ Datachunker's إما صفيف بايت، وهو File أو InputStream

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top