2017-12-10 12 views
0

属性値が配列として格納されているjsonがあり、配列に値を追加してファイルに書き込む必要があります。既存のデータの書き換えを避け、新しい値だけを追加する方法はありますか?ファイル全体を書き込まずにjsonファイルに追加する

-----別のスレッドで次の質問を移動する--------------- 大きなデータセットをファイルインクリメンタルファイル書き込みまたはファイルダンプに書き込むための推奨方法最後のプロセスで?

+1

あなたは2つの無関係な質問をしています。投稿ごとに1つの質問をしてください。あなたのJSONの質問は素晴らしいです。ビッグデータセットの作成に関する第2の質問は第2の質問であるべきであり、それを明確にする必要があります。 – Flimzy

+0

ファイルがJSON配列であるか、値のストリームである必要がありますか?後者は、両方の質問への答えをより簡単にします。 –

+0

@Flimzyが質問を編集しました。 – Abhsk

答えて

1

JSON配列がシンプルな場合は、次のコードを使用できます。このコードでは、JSON配列を手動で作成します。

type item struct { 
    Name string 
} 

func main() { 
    fd, err := os.Create("hello.json") 
    if err != nil { 
     log.Fatal(err) 
    } 

    fd.Write([]byte{'['}) 
    for i := 0; i < 10; i++ { 
     b, err := json.Marshal(item{ 
      "parham", 
     }) 
     if err != nil { 
      log.Fatal(err) 
     } 

     if i != 0 { 
      fd.Write([]byte{','}) 
     } 
     fd.Write(b) 
    } 
    fd.Write([]byte{']'}) 
} 

あなたは各反復の終わりに「]」と書くと、次の反復の開始に戻って求めることができ、各段階で有効な配列を持つようにしたい場合。

+1

あなたの提案をありがとう。私は同様の行を考えていましたが、その後はすべての繰り返しの後に次の手順を実行する必要がありました 1。{{"name": "Batman"}、{"name": "Superman"}} '' _ 2.新しいアイテムを追加する 3. '}}'を再追加してください これらの手順のいずれかが失敗した場合、無効なjsonが発生する可能性があります。また、これを手動で行うと、チャンスのエラーが増える可能性があります。 – Abhsk

+0

はい、私はこれらの問題についてあなたに同意します。 @アブスク –

1

既存のJSONが実際に配列である場合、またはあなたの場合のように配列が最後か唯一のペアであるオブジェクトの場合は、一般的な解決策が最も効果的です。そうでない場合は、を追加の代わりにと挿入します。あなたはおそらくにファイルを読ませたくないでしょう。

一つのアプローチは、あなたが考えていたものよりもはるかに違いはありませんが、いくつかの詳細

  1. それは
  2. その部分を保持「配列で終わる」ことを確認するために、ファイルの末尾を読むを扱う
  3. ファイルをその末尾の配列ブラケットに配置します
  4. 標準のエンコーダから新しいデータの配列を取り出し、その括弧を削除し、必要に応じてカンマを挿入します。
  5. en新しい出力のDは、

    あなたが使用することができ、この試験片のようであるバック

import (
     "bytes" 
     "errors" 
     "io" 
     "io/ioutil" 
     "os" 
     "regexp" 
     "unicode" 
) 

const (
     tailCheckLen = 16 
) 

var (
     arrayEndsObject = regexp.MustCompile("(\\[\\s*)?](\\s*}\\s*)$") 
     justArray  = regexp.MustCompile("(\\[\\s*)?](\\s*)$") 
) 

type jsonAppender struct { 
     f    *os.File 
     strippedBracket bool 
     needsComma  bool 
     tail   []byte 
} 

func (a jsonAppender) Write(b []byte) (int, error) { 
     trimmed := 0 
     if !a.strippedBracket { 
       t := bytes.TrimLeftFunc(b, unicode.IsSpace) 
       if len(t) == 0 { 
         return len(b), nil 
       } 
       if t[0] != '[' { 
         return 0, errors.New("not appending array: " + string(t)) 
       } 
       trimmed = len(b) - len(t) + 1 
       b = t[1:] 
       a.strippedBracket = true 
     } 
     if a.needsComma { 
       a.needsComma = false 
       n, err := a.f.Write([]byte(", ")) 
       if err != nil { 
         return n, err 
       } 
     } 
     n, err := a.f.Write(b) 
     return trimmed + n, err 
} 

func (a jsonAppender) Close() error { 
     if _, err := a.f.Write(a.tail); err != nil { 
       defer a.f.Close() 
       return err 
     } 
     return a.f.Close() 
} 

func JSONArrayAppender(file string) (io.WriteCloser, error) { 
     f, err := os.OpenFile(file, os.O_RDWR, 0664) 
     if err != nil { 
       return nil, err 
     } 

     pos, err := f.Seek(0, io.SeekEnd) 
     if err != nil { 
       return nil, err 
     } 

     if pos < tailCheckLen { 
       pos = 0 
     } else { 
       pos -= tailCheckLen 
     } 
     _, err = f.Seek(pos, io.SeekStart) 
     if err != nil { 
       return nil, err 
     } 

     tail, err := ioutil.ReadAll(f) 
     if err != nil { 
       return nil, err 
     } 

     hasElements := false 

     if len(tail) == 0 { 
       _, err = f.Write([]byte("[")) 
       if err != nil { 
         return nil, err 
       } 
     } else { 
       var g [][]byte 
       if g = arrayEndsObject.FindSubmatch(tail); g != nil { 
       } else if g = justArray.FindSubmatch(tail); g != nil { 
       } else { 
         return nil, errors.New("does not end with array") 
       } 

       hasElements = len(g[1]) == 0 
       _, err = f.Seek(-int64(len(g[2])+1), io.SeekEnd) // 1 for ] 
       if err != nil { 
         return nil, err 
       } 
       tail = g[2] 
     } 

     return jsonAppender{f: f, needsComma: hasElements, tail: tail}, nil 
} 

使用上のオリジナルのエンディング・アレイ・ブラケットに

  • タック尾の残りの部分を置き換えます必要なエンコーダーの設定を変更します。ハードコーディングされた部分のみがneedsCommaを処理していますが、そのための引数を追加できます。

  • 関連する問題