জাভাতে ডিফল্ট চরসেট / এনকোডিং কীভাবে সন্ধান করবেন?


92

সুস্পষ্ট উত্তরটি ব্যবহার করা হয় Charset.defaultCharset()তবে আমরা সম্প্রতি আবিষ্কার করেছি যে এটি সঠিক উত্তর হতে পারে না। আমাকে বলা হয়েছিল যে ফলাফলটি বেশ কয়েকটি অনুষ্ঠানে java.io ক্লাস দ্বারা ব্যবহৃত রিয়েল ডিফল্ট চরসেটের থেকে আলাদা। দেখে মনে হচ্ছে জাভা ডিফল্ট চরসেটের 2 সেট রাখে। কারও কি এই ইস্যুতে অন্তর্দৃষ্টি আছে?

আমরা একটি ব্যর্থ কেস পুনরুত্পাদন করতে সক্ষম হয়েছি। এটি এক ধরণের ব্যবহারকারীর ত্রুটি তবে এটি অন্য সমস্ত সমস্যার মূল কারণটি উন্মোচিত করতে পারে। এখানে কোড,

public class CharSetTest {

    public static void main(String[] args) {
        System.out.println("Default Charset=" + Charset.defaultCharset());
        System.setProperty("file.encoding", "Latin-1");
        System.out.println("file.encoding=" + System.getProperty("file.encoding"));
        System.out.println("Default Charset=" + Charset.defaultCharset());
        System.out.println("Default Charset in Use=" + getDefaultCharSet());
    }

    private static String getDefaultCharSet() {
        OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
        String enc = writer.getEncoding();
        return enc;
    }
}

লিগ্যাসি প্রোটোকলটিতে কিছু মিশ্র এনকোডিং (এএনএসআই / ল্যাটিন -১ / ইউটিএফ -8) মোকাবেলার জন্য আমাদের সার্ভারের ল্যাটিন -১ এ ডিফল্ট চরসেট প্রয়োজন। সুতরাং আমাদের সমস্ত সার্ভারগুলি এই জেভিএম প্যারামিটার দিয়ে চলেছে,

-Dfile.encoding=ISO-8859-1

এখানে জাভা 5 এ ফলাফল,

Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=UTF-8
Default Charset in Use=ISO8859_1

কেউ কোডে ফাইল.ইনকোডিং সেট করে এনকোডিং রানটাইম পরিবর্তন করার চেষ্টা করে। আমরা সবাই জানি যে কাজ করে না। যাইহোক, এটি স্পষ্টতই ডিফল্টচার্সেট () ছুঁড়ে ফেলেছে তবে এটি আউটপুটস্ট্রিম রাইটার দ্বারা ব্যবহৃত প্রকৃত ডিফল্ট চরসেটকে প্রভাবিত করে না।

এটি কি কোনও বাগ বা বৈশিষ্ট্য?

সম্পাদনা: গৃহীত উত্তরগুলি সমস্যার মূল কারণ দেখায়। মূলত, আপনি জাভা 5-এ ডিফল্টচরसेट () বিশ্বাস করতে পারবেন না, এটি আই / ও ক্লাস দ্বারা ব্যবহৃত ডিফল্ট এনকোডিং নয়। দেখে মনে হচ্ছে জাভা 6 এই সমস্যাটিকে সংশোধন করে।


এটি অদ্ভুত, যেহেতু ডিফল্টচ্যারসেটটি স্ট্যাটিক ভেরিয়েবল ব্যবহার করে যা কেবল একবার সেট করা থাকে (ডক্সের প্রতি সম্মান - ভিএম স্টার্টআপে)। আপনি কোন ভিএম বিক্রেতা ব্যবহার করছেন?
বোজহো 14

আমি এটি সান / লিনাক্স এবং অ্যাপল / ওএস এক্স উভয় জাভা 5 এ পুনরুত্পাদন করতে সক্ষম হয়েছি
জেডজেড কোডার

এটি ব্যাখ্যা করে যে ডিফল্টচরसेट () ফলাফলটি কেন ক্যাচ করছে না। আইও ক্লাসগুলির দ্বারা ব্যবহৃত আসল ডিফল্ট চরসেটটি এখনও আমার সন্ধান করতে হবে। অন্য কোথাও ক্যাশেড থাকা অন্য একটি ডিফল্ট অক্ষর থাকতে হবে।
জেডজেড কোডার

@ জেডজেড কোডার, আমি এখনও এটি নিয়ে গবেষণা করছি। কেবলমাত্র আমি জানি যে চরসেট.ডেফৌলিচারসিট () কে জেভিএম 1.5 তে সূর্য.নিও.সি.এস.স্ট্রিমইনকডার থেকে কল করা হয়নি। জেভিএম ১. In-তে চরসেট.দেফৌলিচারসিট () পদ্ধতিটি প্রত্যাশিত ফলাফল প্রদান করা হয়। স্ট্রিমইনকডারটির JVM 1.5 বাস্তবায়ন পূর্ববর্তী এনকোডিংটি কোনওভাবে ক্যাশে করছে।
ব্রুনো কনদে

উত্তর:


62

এটি সত্যিই অদ্ভুত ... একবার সেট হয়ে গেলে, ডিফল্ট চরসেটটি ক্যাশে করা হয় এবং ক্লাস স্মৃতিতে থাকা অবস্থায় এটি পরিবর্তন হয় না। "file.encoding"সম্পত্তি সেট System.setProperty("file.encoding", "Latin-1");করে কিছু হয় না। প্রতিবার Charset.defaultCharset()বলা হয় এটি ক্যাশেড চরসেটটি ফেরত দেয়।

আমার ফলাফলগুলি এখানে:

Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=ISO-8859-1
Default Charset in Use=ISO8859_1

যদিও আমি JVM 1.6 ব্যবহার করছি।

(হালনাগাদ)

ঠিক আছে. আমি আপনার বাগটি JVM 1.5 দিয়ে পুনরুত্পাদন করেছি।

1.5 এর উত্স কোডটির দিকে তাকানো, ক্যাশেড ডিফল্ট চরসেট সেট করা হচ্ছে না। আমি জানি না এটি কোনও ত্রুটিযুক্ত কিনা বা না তবে 1.6 এই প্রয়োগটি পরিবর্তন করে এবং ক্যাশেড অক্ষরটি ব্যবহার করে:

জেভিএম 1.5:

public static Charset defaultCharset() {
    synchronized (Charset.class) {
        if (defaultCharset == null) {
            java.security.PrivilegedAction pa =
                    new GetPropertyAction("file.encoding");
            String csn = (String) AccessController.doPrivileged(pa);
            Charset cs = lookup(csn);
            if (cs != null)
                return cs;
            return forName("UTF-8");
        }
        return defaultCharset;
    }
}

জেভিএম 1.6:

public static Charset defaultCharset() {
    if (defaultCharset == null) {
        synchronized (Charset.class) {
            java.security.PrivilegedAction pa =
                    new GetPropertyAction("file.encoding");
            String csn = (String) AccessController.doPrivileged(pa);
            Charset cs = lookup(csn);
            if (cs != null)
                defaultCharset = cs;
            else
                defaultCharset = forName("UTF-8");
        }
    }
    return defaultCharset;
}

file.encoding=Latin-1পরের বার আপনি যখন ফোন করবেন তখন ফাইলটি এনকোডিং সেট করার পরে Charset.defaultCharset()যা ঘটেছিল তা হ'ল কারণ ক্যাশেড ডিফল্ট চরসেট সেট করা নেই, এটি নামের জন্য উপযুক্ত অক্ষরটি সন্ধান করার চেষ্টা করবে Latin-1। এই নামটি পাওয়া যায় নি, কারণ এটি ভুল, এবং ডিফল্টটি দেয় UTF-8

কেন যেমন আইও ক্লাস যেমন OutputStreamWriterঅপ্রত্যাশিত ফলাফল প্রত্যাবর্তন করে, জেভিএম 1.5 এবং জেভিএম 1.6 এর
জন্য sun.nio.cs.StreamEncoder(এই আইও ক্লাসগুলির দ্বারা ডাইনী ব্যবহৃত হয়) বাস্তবায়ন আলাদা। JVM 1.6 বাস্তবায়ন Charset.defaultCharset()ডিফল্ট এনকোডিং পাওয়ার পদ্ধতির ভিত্তিতে তৈরি করা হয় , যদি কোনও আইও ক্লাসে সরবরাহ না করা হয়। জেভিএম 1.5 বাস্তবায়ন Converters.getDefaultEncodingName();ডিফল্ট চরসেটটি পেতে একটি পৃথক পদ্ধতি ব্যবহার করে। এই পদ্ধতিটি জেভিএম সূচনাতে সেট করা ডিফল্ট চরসেটের নিজস্ব ক্যাশে ব্যবহার করে:

জেভিএম 1.6:

public static StreamEncoder forOutputStreamWriter(OutputStream out,
        Object lock,
        String charsetName)
        throws UnsupportedEncodingException
{
    String csn = charsetName;
    if (csn == null)
        csn = Charset.defaultCharset().name();
    try {
        if (Charset.isSupported(csn))
            return new StreamEncoder(out, lock, Charset.forName(csn));
    } catch (IllegalCharsetNameException x) { }
    throw new UnsupportedEncodingException (csn);
}

জেভিএম 1.5:

public static StreamEncoder forOutputStreamWriter(OutputStream out,
        Object lock,
        String charsetName)
        throws UnsupportedEncodingException
{
    String csn = charsetName;
    if (csn == null)
        csn = Converters.getDefaultEncodingName();
    if (!Converters.isCached(Converters.CHAR_TO_BYTE, csn)) {
        try {
            if (Charset.isSupported(csn))
                return new CharsetSE(out, lock, Charset.forName(csn));
        } catch (IllegalCharsetNameException x) { }
    }
    return new ConverterSE(out, lock, csn);
}

তবে আমি মন্তব্যে একমত। আপনি এই সম্পত্তি উপর নির্ভর করা উচিত নয় । এটি বাস্তবায়নের বিশদ।


এই ত্রুটিটি পুনরুত্পাদন করতে আপনার জাভা 5 এ থাকা আবশ্যক এবং আপনার জেআরই ডিফল্ট এনকোডিংটি অবশ্যই ইউটিএফ -8 হওয়া উচিত।
জেডজেড কোডার ১

4
এটি বাস্তবায়নের জন্য লিখছেন, বিমূর্ততা নয়। আপনি যদি অনিবন্ধিত স্টাফের উপর নির্ভর করেন তবে প্ল্যাটফর্মটির নতুন সংস্করণে আপগ্রেড করার সময় আপনার কোডটি বিরতি হয়ে গেলে অবাক হবেন না।
ম্যাকডোয়েল

24

এটি কি কোনও বাগ বা বৈশিষ্ট্য?

অপরিবর্তিত আচরণের মতো দেখায়। আমি জানি যে, বাস্তবে, আপনি একটি কমান্ড-লাইন সম্পত্তি ব্যবহার করে ডিফল্ট এনকোডিং পরিবর্তন করতে পারেন, তবে আপনি যখন এটি করেন তখন সংজ্ঞায়িত হয় তা আমি মনে করি না।

বাগ সম্পত্তি: 4153515 এই সম্পত্তিটি সেট করার সমস্যাগুলির জন্য:

এটি একটি বাগ না। J2SE প্ল্যাটফর্মের বিশদকরণের দ্বারা "file.encoding" সম্পত্তিটির প্রয়োজন হয় না; এটি সূর্যের বাস্তবায়নগুলির অভ্যন্তরীণ বিশদ এবং ব্যবহারকারীর কোড দ্বারা এটি পরীক্ষা করা বা সংশোধন করা উচিত নয়। এটি কেবল পঠনযোগ্য হওয়ার জন্যও; প্রোগ্রামটি কার্যকর করার সময় কমান্ড লাইনে বা অন্য কোনও সময়ে নির্বিচার মানগুলিতে এই সম্পত্তিটির সেটিং সমর্থন করা প্রযুক্তিগতভাবে অসম্ভব।

ভিএম এবং রানটাইম সিস্টেম দ্বারা ব্যবহৃত ডিফল্ট এনকোডিং পরিবর্তন করার পছন্দের উপায়টি আপনার জাভা প্রোগ্রামটি শুরু করার আগে অন্তর্নিহিত প্ল্যাটফর্মের লোকেল পরিবর্তন করা।

লোকেরা কমান্ড লাইনে এনকোডিংটি সেট করতে দেখলে আমি ক্রিঙ্ক করি - আপনি জানেন না যে কোন কোডটি প্রভাব ফেলবে।

আপনি যদি ডিফল্ট এনকোডিংটি ব্যবহার করতে না চান তবে উপযুক্ত পদ্ধতি / কনস্ট্রাক্টরের মাধ্যমে আপনি যে এনকোডিংটি স্পষ্টভাবে চান তা সেট করুন ।


4

প্রথমত, ল্যাটিন -1 ISO-8859-1 এর সমান, সুতরাং, ডিফল্টটি আপনার জন্য ইতিমধ্যে ঠিক ছিল। ঠিক?

আপনি আপনার কমান্ড লাইন প্যারামিটার সহ ISO-8859-1 এ সাফল্যের সাথে এনকোডিংটি সেট করেছেন। আপনি এটিকে প্রোগ্রামিনালি "ল্যাটিন -১" তে সেট করেছেন, তবে এটি জাভার জন্য কোনও ফাইল এনকোডিংয়ের স্বীকৃত মান নয়। Http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html দেখুন

আপনি যখন এটি করেন, উত্সের দিকে তাকানো থেকে চরসেটটি ইউটিএফ -8 এ পুনরায় সেট করে। এটি অন্তত বেশিরভাগ আচরণের ব্যাখ্যা করে।

আমি জানি না কেন আউটপুট স্ট্রিম রাইটার ISO8859_1 দেখায়। এটি ক্লোজড সোর্স সান.মিস্ক। * ক্লাসে প্রতিনিধিত্ব করে। আমি অনুমান করছি এটি একই পদ্ধতিটির মাধ্যমে এনকোডিংয়ের সাথে বেশ কার্যকর নয়, যা অদ্ভুত।

তবে অবশ্যই আপনার কোডটি কীভাবে এনকোডিংয়ের অর্থ তা বোঝানো উচিত। আমি কখনই প্ল্যাটফর্মের ডিফল্টর উপর নির্ভর করি না।


4

আচরণটি আসলে তেমন অদ্ভুত নয়। ক্লাসগুলির বাস্তবায়নের দিকে নজর দিলে এটি ঘটে:

  • Charset.defaultCharset() জাভা 5 তে নির্ধারিত অক্ষর সেটটি ক্যাশে করছে না।
  • সিস্টেমের সম্পত্তি "ফাইল.ইনকোডিং" সেট করা এবং Charset.defaultCharset()আবার অনুরোধ করা সিস্টেম সম্পত্তিটির দ্বিতীয় মূল্যায়ন ঘটায়, "ল্যাটিন -১" নামের কোনও অক্ষর সেট পাওয়া যায়নি, সুতরাং Charset.defaultCharset()"ইউটিএফ -8" এ ডিফল্ট রয়েছে।
  • OutputStreamWriterতবে ডিফল্ট অক্ষর সেট ক্যাশে করা হয় এবং সম্ভবত VM- র আরম্ভের সময় ইতিমধ্যে ব্যবহার করা হয়, যাতে তার ডিফল্ট অক্ষর সেট বিচ্যুত করে থেকে Charset.defaultCharset()যদি সিস্টেম সম্পত্তি "file.encoding" রানটাইম এ পরিবর্তন করা হয়েছে।

ইতিমধ্যে চিহ্নিত হিসাবে, VM যেমন একটি পরিস্থিতিতে আচরণ করা আবশ্যক এটি নথিভুক্ত করা হয় না। Charset.defaultCharset()এপিআই ডকুমেন্টেশন কিভাবে ডিফল্ট অক্ষর সেট নির্ধারণ করা হয়, শুধুমাত্র উল্লেখ এটি সাধারণত VM- র সূচনার সময় সম্পন্ন করা হয়, অপারেটিং সিস্টেম ডিফল্ট অক্ষর সেট অথবা ডিফল্ট লোকেল মত বিষয়গুলির উপর ভিত্তি করে খুব সুনির্দিষ্ট নয়।


3

আমি সার্ভারের ডিফল্ট অক্ষর সেটটি পরিবর্তন করতে WAS সার্ভারে vm আর্গুমেন্টকে -Dfile.encoding = UTF-8 হিসাবে সেট করেছি।


1

চেক

System.getProperty("sun.jnu.encoding")

এটি আপনার সিস্টেমের কমান্ড লাইনে ব্যবহৃত এনকোডিংয়ের মতো বলে মনে হচ্ছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.