我的家園

          我的家園
            GridFSFile 類表示 GridFS 中的文件的信息,它是一個抽象類,分別被 GridFSDBFile (表示從數據庫中讀取的文件) 和 GridFSInputFile(表示將要保存到數據庫中的文件 ) 繼承。

            GridFSFile 類包含下列屬性(相應地有一系列的  get 方法)
              Object _id;                // 文件的唯一標識
              String _filename;          // 文件的名稱
              String _contentType;       // 文件內容類型
              long _length;              // 文件長度
              long _chunkSize;           // 文件分塊大小
              Date _uploadDate;          // 更新時間
              List<String> _aliases;     // 別名
              DBObject _extradata = new BasicDBObject();  //額外信息
              String _md5;               // md5 值
          

            此外它還提供保存文件信息的 save 方法:
              // 保存文件
              public void save(){
                  if ( _fs == null )
                      throw new MongoException( "need _fs" );
                  _fs._filesCollection.save( this );
              }
          

          GridFSDBFile (從數據庫中讀取的文件)

            【將文件寫入輸出流】

            GridFSDBFile 的 writeTo 方法可以將文件寫入輸出流,以達到讀取文件數據的目的。
              // 將文件寫入輸出流
              public long writeTo( OutputStream out )
                  throws IOException {
                  final int nc = numChunks();
          
                  // 遍歷文件塊,一次寫入到輸出流中
                  for ( int i=0; i<nc; i++ ){
                      out.write( getChunk( i ) );
                  }
                  return _length;
              }
          
              // 獲取特定的文件塊
              byte[] getChunk( int i ){
                  if ( _fs == null )
                      throw new RuntimeException( "no gridfs!" );
                  
                  // 調用 GridFS 的 _chunkCollection 的 findOne 方法
                  // _chunkCollection 中存放了文件數據
                  // 查詢時指定了參數 files_id (文件的唯一標識) 和 n (序號)
                  DBObject chunk = _fs._chunkCollection.findOne( BasicDBObjectBuilder.start( "files_id" , _id ).add( "n" , i ).get() );
                  if ( chunk == null )
                      throw new MongoException( "can't find a chunk!  file id: " + _id + " chunk: " + i );
          
                  // 獲取文件塊數據
                  return (byte[])chunk.get( "data" );
              }
          


            【獲取輸入流】

            另一種讀取數據的方式是直接獲取輸入流。

              // 獲取輸入流,用于讀取數據
              public InputStream getInputStream(){
                  return new MyInputStream();
              }
          

              GridFSFile.MyInputStream 的 read 方法實現如下:
                  // 讀取數據
                  // b 存放數據的字節數組
                  // off 偏移量
                  // len 長度
                  public int read(byte[] b, int off, int len){
                      // 偏移量超過文件大小
                      if ( _data == null || _offset >= _data.length ){
                          // 已經讀完
                          if ( _nextChunk >= _numChunks )
                              return -1;
                          
                          // 讀取一塊數據,以備使用
                          _data = getChunk( _nextChunk );
                          _offset = 0;
                          _nextChunk++;
                      }
          
                      // r:將要讀取的數據的長度
                      int r = Math.min( len , _data.length - _offset );
          
                      // 將 _data 中指定偏移量和長度的數據復制到 b 中
                      System.arraycopy( _data , _offset , b , off , r );
          
                      // 增加偏移量
                      // 在 MyInputStream 內部記錄當前的數據塊讀取到哪里了
                      // 下次再從這里開始讀取
                      _offset += r;
          
                      // 返回讀取的長度
                      return r;
                  }
          


            【刪除操作】

            GridFSDBFile 還提供從 GridFS 中刪除文件的方法,實際上相當于調用  GridFS 的 remove 方法。
              // 從 GridFS 的 _filesCollection 和 _chunkCollection 中刪除文件
              // 與 GridFS.remove 方法的實現相似, 實際上相當于調用  _fs.remove(_id)
              void remove(){ 
                  _fs._filesCollection.remove( new BasicDBObject( "_id" , _id ) );
                  _fs._chunkCollection.remove( new BasicDBObject( "files_id" , _id ) );
              }
          

          GridFSInputFile 準備寫入數據庫的文件

            GridFSInputFile 可以獲得輸出流,從而寫入需要保存的數據,寫入完畢后通過 close 方法提交修改。
              // 獲取輸出流
              public OutputStream getOutputStream() {
                  if ( _outputStream == null ) {
                      _outputStream = new MyOutputStream();
                  }
                  return _outputStream;
              }
          


            GridFSInputFile.MyOutputStream 的 write 方法的實現如下:
                  public void write( byte[] b , int off , int len ) throws IOException {
                      int offset = off;
                      int length = len;
                      int toCopy = 0;
                      while ( length > 0 ) {
                          // 計算每次需要寫入的長度
                          toCopy = length;
                          if ( toCopy > _chunkSize - _currentBufferPosition ) {
                              toCopy = (int) _chunkSize - _currentBufferPosition;
                          }
          
                          // 復制數據
                          System.arraycopy( b, offset, _buffer, _currentBufferPosition, toCopy );
          
                          // 修改偏移量
                          _currentBufferPosition += toCopy;
                          offset += toCopy;
                          length -= toCopy;
          
                          // 已經到達文件塊的結尾,寫入數據庫
                          if ( _currentBufferPosition == _chunkSize ) {
                              _dumpBuffer( false );
                          }
                      }
                  }
          
              // 將緩沖區中的數據寫入數據庫中
              // writePartial 為 true 表示不寫入整塊的數據,這通常用于寫入文件數據的結尾部分。
              private void _dumpBuffer( boolean writePartial ) {
                  if ( ( _currentBufferPosition < _chunkSize ) && !writePartial ) {
                      // 文件塊不完整,返回
                      return;
                  }
                  if (_currentBufferPosition == 0) {
                      // 塊為空,返回
                      return;
                  }
          
                  // 復制數據
                  byte[] writeBuffer = _buffer;
                  if ( _currentBufferPosition != _chunkSize ) {
                      writeBuffer = new byte[_currentBufferPosition];
                      System.arraycopy( _buffer, 0, writeBuffer, 0, _currentBufferPosition );
                  }
          
                  // 保存文件數據到數據庫
                  DBObject chunk = BasicDBObjectBuilder.start()
                          .add( "files_id", _id )
                          .add( "n", _currentChunkNumber )
                          .add( "data", writeBuffer ).get();
                  _fs._chunkCollection.save( chunk );
          
                  // 改變偏移量等收尾工作
                  _currentChunkNumber++;
                  _totalBytes += writeBuffer.length;
                  _messageDigester.update( writeBuffer );
                  _currentBufferPosition = 0;
              }
          

            需要特別注意的是以下語句:
                  // 保存文件數據到數據庫
                  DBObject chunk = BasicDBObjectBuilder.start()
                          .add( "files_id", _id )
                          .add( "n", _currentChunkNumber )
                          .add( "data", writeBuffer ).get();
                  _fs._chunkCollection.save( chunk );
          

            借助 DBCollection.save 保存了數據。構造的 DBObject 包含三個屬性:files_id (文件標識)、n(文件塊序號)和 data(文件數據)




          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 鄂州市| 乳山市| 勐海县| 武穴市| 翁源县| 无为县| 涿州市| 高阳县| 桐柏县| 刚察县| 临武县| 宕昌县| 阳信县| 信宜市| 五家渠市| 滕州市| 尼玛县| 泊头市| 称多县| 松阳县| 克什克腾旗| 华蓥市| 马尔康县| 砚山县| 舞阳县| 蓬安县| 广德县| 五大连池市| 吉首市| 温州市| 体育| 那曲县| 屏南县| 永善县| 临安市| 湘潭市| 河北省| 诸暨市| 淅川县| 堆龙德庆县| 余江县|