属性値が配列として格納されているjsonがあり、配列に値を追加してファイルに書き込む必要があります。既存のデータの書き換えを避け、新しい値だけを追加する方法はありますか?ファイル全体を書き込まずにjsonファイルに追加する
-----別のスレッドで次の質問を移動する--------------- 大きなデータセットをファイルインクリメンタルファイル書き込みまたはファイルダンプに書き込むための推奨方法最後のプロセスで?
属性値が配列として格納されているjsonがあり、配列に値を追加してファイルに書き込む必要があります。既存のデータの書き換えを避け、新しい値だけを追加する方法はありますか?ファイル全体を書き込まずにjsonファイルに追加する
-----別のスレッドで次の質問を移動する--------------- 大きなデータセットをファイルインクリメンタルファイル書き込みまたはファイルダンプに書き込むための推奨方法最後のプロセスで?
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。{{"name": "Batman"}、{"name": "Superman"}} '' _ 2.新しいアイテムを追加する 3. '}}'を再追加してください これらの手順のいずれかが失敗した場合、無効なjsonが発生する可能性があります。また、これを手動で行うと、チャンスのエラーが増える可能性があります。 – Abhsk
はい、私はこれらの問題についてあなたに同意します。 @アブスク –
既存のJSONが実際に配列である場合、またはあなたの場合のように配列が最後か唯一のペアであるオブジェクトの場合は、一般的な解決策が最も効果的です。そうでない場合は、を追加の代わりにと挿入します。あなたはおそらくにファイルを読ませたくないでしょう。
一つのアプローチは、あなたが考えていたものよりもはるかに違いはありませんが、いくつかの詳細
あなたが使用することができ、この試験片のようであるバック
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
を処理していますが、そのための引数を追加できます。
あなたは2つの無関係な質問をしています。投稿ごとに1つの質問をしてください。あなたのJSONの質問は素晴らしいです。ビッグデータセットの作成に関する第2の質問は第2の質問であるべきであり、それを明確にする必要があります。 – Flimzy
ファイルがJSON配列であるか、値のストリームである必要がありますか?後者は、両方の質問への答えをより簡単にします。 –
@Flimzyが質問を編集しました。 – Abhsk