これはとても簡単な問題のように思えますが、私はどこにも解決策を見つけることができないようです。私の同僚と私は、Foxproxmlダンプ機能を利用するアプリケーションに取り組んでいます。それはうまく機能しますが、いくつかのサイズの制約に基づいてテーブルを複数のファイルに分割したいと考えています。
これは簡単な部分のようです。Foxproでカーソルのサイズをどのように見つけますか?
RECSIZE() は、個々の行の長さをバイト単位で返します。その倍の RECCOUNT() がサイズを示します。すでに説明した要素はすべて正確です。
メモ フィールドに関して、それらがどのくらい大きいかを知る必要がある場合は、「MemoLength」のテーブル構造に新しい整数列を追加することをお勧めします。それで
すべての memoLength を len( alltrim( YourMemoField )) に置き換えます
次に、MemoLength を使用して、抽出する残りの RECSIZE() * 行でこの列のサイズを考慮に入れることで、内訳グループの決定に役立てることができます。
さらに、リンクとして使用できるテーブルの主キー列に基づいてクエリを実行し、次のようなことを行うことができます...
YourPrimaryKey, len( alltrim( YourMemoField )) を MemoLength として YourTable からカーソルに選択 SomeHoldingCursor readwrite
.. または、選択
テーブルMemSizeTableに
MemSizeTable にインデックスを作成すると、その結合を使用して詳細情報を取得できます。このようにして、元のレコード サイズを歪めたり、元のテーブル構造を混乱させたりすることはありませんが、リレーションを使用すると、必要な要素を抽出できます。
ファイル サイズを意味する場合は、エイリアスとしてカーソルを指定して DBF() 関数を呼び出し、戻り値の拡張子が .dbf であることを確認し、ファイル関数を使用してファイル サイズを読み取ることで、カーソルが関連するファイルを見つけることができます。ただし、カーソルはメモリ内にある可能性があります(私の記憶が正しければ、報告された「ファイル名」には .tmp 拡張子が付きます)。そのため、代わりに RECCOUNT() (行数を取得するため) を AFIELDS() と組み合わせて使用することもできます (各行のサイズを取得する) を使用して、ファイル サイズを概算します。(生成するクエリに NOFILTER 句を含めることで、インメモリ カーソルを強制的にディスクに書き込むことができます)
これは、サンプル カーソルと偽のレコードに基づいて完全に機能するものです...重要な機能は DumpXML() ルーチンであり、ダンプするファイルのエイリアス、つまり上限にしたいファイルごとのサイズが必要です (in "k " サイズ)、および XML をダンプするファイル名のプレフィックス。MyXMLOutput1.xml、MyXMLOutput2.xml、MyXMLOutput3.xml などの順序付けを自動生成しますが、多くのインスタンスを実行する必要があります。15分くらいかかりました。
CREATE CURSOR SomeTest ;
( SomeField1 c(10),;
AnotherField i,;
SomeNumber N(8,2),;
MemoFld m,;
SomeDateTime t;
)
INSERT INTO SomeTest VALUES ( "testchar10", 9403, 12345.78, "some memo value string", DATETIME() )
DumpXML( ALIAS(), 300, "MyXML" )
FUNCTION dumpXML
LPARAMETERS cAliasName, nSizeLimit, cNameOfXMLOutput
IF NOT USED( cAliasName )
RETURN ""
ENDIF
*/ Assume size limit in "k"
nSizeLimit = nSizeLimit * 1024
SELECT ( cAliasName )
*/ Get a copy of the structure without disrupting original
USE IN SELECT( "MySample" ) && pre-close in case left open from prior cycle
SELECT * ;
FROM ( cAliasName ) ;
WHERE RECNO() = 1;
INTO CURSOR MySample READWRITE
SELECT MySample
*/ Populate each field with maximum capacities... typically
*/ critical for your char based fields
AFIELDS( aActualStru )
cMemoFields = ""
lHasMemoFields = .f.
FOR I = 1 TO FCOUNT()
cFieldName = FIELD(I)
DO CASE
CASE aActualStru[i,2] = "C"
replace &cFieldName WITH REPLICATE( "X", aActualStru[i,3] )
CASE aActualStru[i,2] = "L"
replace &cFieldName WITH .T.
CASE aActualStru[i,2] = "D"
replace &cFieldName WITH DATE()
CASE aActualStru[i,2] = "T"
replace &cFieldName WITH DATETIME()
CASE aActualStru[i,2] = "M"
*/ Default memo as a single character to ensure
*/ closing field name </endoffield> included in XML
replace &cFieldName WITH "X"
*/ if a MEMO field, add this element to a string
*/ to be macro'd to detect its size... Each record
*/ can contain MORE than one memo field...
*/ Ex: + LEN( ALLTRIM( MemoFld ))
lHasMemoFields = .T.
cMemoFields = cMemoFields + " + len( ALLTRIM( " + cFieldName + " ))"
CASE aActualStru[i,2] = "I"
*/ Integer, force to just 10 1's
replace &cFieldName WITH 1111111111
CASE aActualStru[i,2] = "N"
*/ Actual numeric and not an integer, double or float
*/ Allow for full length plus decimal positions
NumValue = VAL( REPLICATE( "9", aActualStru[i,3] - aActualStru[i,4] - 1 );
+ "." + REPLICATE( "9", aActualStru[i,4] ))
replace &cFieldName WITH NumValue
ENDCASE
ENDFOR
*/ Strip leading " + " from the string in case multiple fields
IF lHasMemoFields
cMemoFields = SUBSTR( cMemoFields, 3 )
ENDIF
cXML = ""
LOCAL oXML as XMLAdapter
oXML = CREATEOBJECT( "XMLAdapter" )
oXML.AddTableSchema( "MySample" )
oXML.ToXML( "cXML", "", .f. )
*/ Now, determine the size of the per record at its full length -- less memo
nSizeOfPerRecord = LEN( STREXTRACT( cXML, "<MySample>", "</MySample>", 1, 4 ))
*/ and the rest of the header per XML dump
nSizeOfSchema = LEN( cXML ) - nSizeOfPerRecord
*/ Now, back to the production alias to be split
SELECT( cAliasName )
nNewSize = 0
nXMLCycle = 0
*/ if we just started, or finished writing another block
*/ and need to generate a new group of XML dump reset size
nNewSize = nSizeOfSchema
*/ Always blank out the temp cursor for each batch...
SELECT MySample
ZAP
SELECT ( cAliasName )
SCAN
IF lHasMemoFields
nAllMemoSizes = &cMemoFields
ELSE
nAllMemoSizes = 0
ENDIF
IF nNewSize + nSizeOfPerRecord + nAllMemoSizes > nSizeLimit
*/ The upcoming record will have exceeded capacity, finish XML
*/ with all records up to this point
nXMLCycle = nXMLCycle + 1
cNewFile = FULLPATH( cNameOfXMLOutput + ALLTRIM( STR( nXMLCycle )) + ".XML" )
oXML = CREATEOBJECT( "XMLAdapter" )
oXML.AddTableSchema( "MySample" )
*/ Generate the XML cycle of these qualified records...
oXML.ToXML( cNewFile, "", .t. )
*/ restart for next pass of data
nNewSize = nSizeOfSchema
*/ Always blank out the temp cursor for each batch...
SELECT MySample
ZAP
ENDIF
*/ Add record to total size...
nNewSize = nNewSize + nSizeOfPerRecord + nAllMemoSizes
*/ we have a record to be included in segment dump...
*/ scatter from the original table and gather into the temp
SCATTER MEMO NAME oFromOriginal
SELECT MySample
APPEND BLANK
GATHER MEMO NAME oFromOriginal
*/ back to original table driving the XML Dump process
SELECT ( cAliasName )
ENDSCAN
*/ if the "MyTable" has records not yet flushed from limit, write that too
IF RECCOUNT( "MySample" ) > 0
*/ The upcoming record will have exceeded capacity, finish XML
*/ with all records up to this point
nXMLCycle = nXMLCycle + 1
cNewFile = FULLPATH( cNameOfXMLOutput + ALLTRIM( STR( nXMLCycle )) + ".XML" )
oXML = CREATEOBJECT( "XMLAdapter" )
oXML.AddTableSchema( "MySample" )
*/ Generate the XML cycle of these qualified records...
oXML.ToXML( cNewFile, "", .t. )
ENDIF
*/ Done with the "MySample" for cursor to XML analysis...
USE IN SELECT( "MySample" )
ENDFUNC