LoginSignup
8
5

More than 5 years have passed since last update.

C# で Java の properties ファイルを読む

Posted at

はじめに

Stack Overflow に Can .NET load and parse a properties file equivalent to Java Properties class?” (January, 2009) という質問があり、Java の properties ファイルを C# で読む方法を尋ねている。質問者のように、既存の properties ファイルに変更を加えずにそのまま C# で読みたいというケースは存在する。

当該質問にはコード付きの回答が幾つか寄せられているが、私の回答を除き、いずれの実装も実用には耐えられない。存在しない仕様を勝手に追加しているものまである。;' をコメント行開始文字として扱ったり、プロパティー値を囲む引用符を勝手に削除したり。

やはり自作するしかない。

Properties ファイルの仕様

Java properties ファイルの仕様は java.util.Properties.load(java.io.Reader) の JavaDoc に書かれている。問題は、みんなが想像するよりも少し仕様が複雑だということだ。全てを網羅しているわけではないが、特に考慮すべき点は次のとおり。

  1. 行には、自然行論理行の二種類がある。
  2. 自然行は \n, \r, \r\n もしくはストリームの末尾で区切られる。
  3. 論理行は、バックスラッシュを使用して行末記号シーケンスをエスケープすることで、隣接する複数の自然行にまたがることがある。
  4. 論理行内の二番目以降の自然行の先頭の空白文字群は捨てられる。
  5. 空白文字とは、スペース (, \u0020)、タブ (\t, \u0009)、ラインフィード (\f, \u000C) である。
  6. 仕様で明確に述べられているように、「行末記号がエスケープされているかどうかを判定する場合、行末記号シーケンスの前の文字を調べるだけでは十分ではありません。行末記号がエスケープされるためには、連続した奇数のバックスラッシュが存在する必要があります。入力は左から右に処理されるため、行末記号の前(またはほかの場所)に連続したバックスラッシュが2n (ゼロでない偶数)個存在する場合、エスケープ処理後にn個のバックスラッシュがエンコードされます。」
  7. = がキーと値の区切り文字として使用される。
  8. : もキーと値の区切り文字として使用される。
  9. キーと値の間の区切り文字は省略可能。
  10. コメント行は、最初の非空白文字として # もしくは ! を持つ。つまり、#! の前の空白文字群は許容される。
  11. 行末記号をバックスラッシュでエスケープしても、コメント行を複数行にまたがらせることはできない。
  12. 仕様で明確に述べらているとおり、=:、空白文字もバックスラッシュでエスケープすることによりキーに埋め込むことができる。
  13. 行末記号でさえ、\r\n というエスケースシーケンスを用いることで含めることができる。
  14. 値が省略された場合、空文字列として扱う。
  15. \uxxxx は Unicode 文字をあらわす。
  16. 有効なエスケープ文字を構成しない文字の前に置かれたバックスラッシュはエラーとして扱われず、単にドロップされる。

Properties ファイルの例

そういうわけで、例えば test.properties が次の内容を持っている場合

# A comment line that starts with '#'.
   # This is a comment line having leading white spaces.
! A comment line that starts with '!'.

key1=value1
  key2 : value2
    key3 value3
key\
  4=value\
    4
\u006B\u0065\u00795=\u0076\u0061\u006c\u0075\u00655
\k\e\y\6=\v\a\lu\e\6

\:\ \= = \\colon\\space\\equal

次のキーバリューペア群として解釈されるべきである。

キー
key1 value1
key2 value2
key3 value3
key4 value4
key5 value5
key6 value6
: = \colon\space\equal

コード例

NuGet パッケージ「Authlete.Authlete」に含まれる PropertiesLoader クラスは Properties ファイルの仕様を解釈することができる。次のコード例は

using System;
using System.IO;
using System.Collections.Generic;
using Authlete.Util;

namespace MyApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            string file = "test.properties";
            IDictionary<string, string> properties;

            using (TextReader reader = new StreamReader(file))
            {
                properties = PropertiesLoader.Load(reader);
            }

            foreach (var entry in properties)
            {
                Console.WriteLine($"{entry.Key} = {entry.Value}");
            }
        }
    }
}

次の出力を生成する。

key1 = value1
key2 = value2
key3 = value3
key4 = value4
key5 = value5
key6 = value6
: = = \colon\space\equal

Java での同様のコードは次のとおり。

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

public class Program
{
    public static void main(String[] args) throws IOException
    {
        String file = "test.properties";
        Properties properties = new Properties();

        try (Reader reader = new FileReader(file))
        {
             properties.load(reader);
        }

        for (Map.Entry<Object, Object> entry : properties.entrySet())
        {
            System.out.format("%s = %s\n", entry.getKey(), entry.getValue());
        }    
    }
}

ソースコード

PropertiesLoader.cs のソースコードは authlete-csharp 内に存在する。また、PropertiesLoader 用の xUnit テスト群は PropertiesLoaderTest.cs 内に記述されている。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5