将文件使用base64存入数据库并在微信小程序中实现文件下载

发布于:2025-07-04 ⋅ 阅读:(12) ⋅ 点赞:(0)

文件存储最基础的两个字段是文件内容和文件名称,在数据中FileContent的数据类型为varbinary(max) (这种方式的弊端是不能大量存储文件,会占用数据库的大量内存)

现在将文件通过文件的完整路径,获取文件的二进制流和文件名(包含后缀)

filePath是文件的完整路径

   byte[] FileData = File.ReadAllBytes(filePath);
   // 获取文件名(带扩展名)
   string fileNameWithExtension = Path.GetFileName(filePath);

 

然后使用参数化的方式将byte[]类型数据存入数据库中

现在我们将文件从数据库中读出来

取出文件内容的核心代码逻辑是把取出的二进制数据转为base64类型字符,并取出文件名字(文件的基本信息存储在以下类中)

微信小程序中页面效果图如下:(暂时只包含了文件名称和下载文件的操作)

 

  <!-- 新增文件下载栏 -->
  <view class="file-download-section">
    <!-- 文件图标占位(根据文件类型显示不同图标) -->
    <view class="file-icon {{fileTypeClass}}">
      <text class="file-icon-text">{{fileIcon}}</text>
    </view>
    
    <view class="file-info">
      <view class="file-name">{{fileName || '未命名文件'}}</view>
    </view>
    
    <button class="download-btn" bindtap="handleDownload">
      <text class="download-btn-text">{{isDownloading ? '下载中...' : '下载文件'}}</text>
    </button>
  </view>
/* 文件下载栏样式 */
.file-download-section {
  display: flex;
  align-items: center;
  padding: 24rpx 30rpx;
  background-color: #ffffff;
  border-radius: 12rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  margin-bottom: 30rpx;
}

/* 文件图标样式 */
.file-icon {
  width: 80rpx;
  height: 80rpx;
  border-radius: 8rpx;
  background-color: #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 20rpx;
  font-size: 40rpx;
}

/* 不同文件类型的图标样式 */
.file-icon.pdf {
  background-color: #e6f7ff;
  color: #1890ff;
}
.file-icon.doc {
  background-color: #f6ffed;
  color: #52c41a;
}
.file-icon.jpg, .file-icon.png {
  background-color: #fff3e0;
  color: #fa8c16;
}
.file-icon.zip {
  background-color: #fce8e6;
  color: #ff4d4f;
}

/* 文件信息区域样式 */
.file-info {
  flex: 1;
  min-width: 0;
  margin-right: 20rpx;
}

.file-name {
  font-size: 28rpx;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 6rpx;
}

.file-size {
  font-size: 24rpx;
  color: #999;
}

/* 下载按钮样式 */
.download-btn {
  min-width: 160rpx;
  height: 70rpx;
  line-height: 70rpx;
  padding: 0;
  background-color: #1890ff;
  color: #ffffff;
  border-radius: 35rpx;
  font-size: 28rpx;
}

.download-btn-text {
  display: block;
}

接下来需要js文件将base64字符转为可使用的本地文件缓存地址


  // Base64 解码实现 (替代浏览器的 atob)
  function atob(base64) {
    // Base64 字符表
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    
    // 移除空格并验证长度
    base64 = base64.replace(/\s/g, '');
    if (base64.length % 4 !== 0) {
      throw new Error('Invalid base64 string');
    }
    
    let output = '';
    let i = 0;
    
    // 解码逻辑
    while (i < base64.length) {
      const enc1 = chars.indexOf(base64.charAt(i++));
      const enc2 = chars.indexOf(base64.charAt(i++));
      const enc3 = chars.indexOf(base64.charAt(i++));
      const enc4 = chars.indexOf(base64.charAt(i++));
      
      const chr1 = (enc1 << 2) | (enc2 >> 4);
      const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      const chr3 = ((enc3 & 3) << 6) | enc4;
      
      output += String.fromCharCode(chr1);
      
      if (enc3 !== 64) {
        output += String.fromCharCode(chr2);
      }
      
      if (enc4 !== 64) {
        output += String.fromCharCode(chr3);
      }
    }
    return output;
  }

function base64ToArrayBuffer(base64) {
  const base64Str = base64.replace(/^data:image\/\w+;base64,/, '');
  const binary = atob(base64Str);
  const len = binary.length;
  const buffer = new ArrayBuffer(len);
  const view = new Uint8Array(buffer);
  
  for (let i = 0; i < len; i++) {
    view[i] = binary.charCodeAt(i);
  }
  
  return buffer;
}

function downloadBase64File(base64Str, fileName) {
  return new Promise((resolve, reject) => {
    try {
      const buffer = base64ToArrayBuffer(base64Str);
      const fs = wx.getFileSystemManager();
      const tempFilePath = `${wx.env.USER_DATA_PATH}/${fileName || 'download_' + Date.now()}`;
      console.log(tempFilePath)
      fs.writeFile({
        filePath: tempFilePath,
        data: buffer,
        success: () => {
          wx.getFileSystemManager().saveFile({
            tempFilePath: tempFilePath,
            success: (res) => resolve(res.savedFilePath),
            fail: (err) => reject(err)
          });
        },
        fail: (err) => reject(err)
      });
    } catch (error) {
      reject(error);
    }
  });
}

export { downloadBase64File };

 在这里我们需要将这个文件新建到util文件下

 在微信小程序中通过接口请求后获取到以上的文件信息 

 

 最后实现方法(以上参数中的DocumentContent、FileName分别赋值给data中的fileContent、fileName)

下载文件核心代码:

getBase64FromServer(){
    return this.data.fileContent;
  },

  handleDownload() {
    const base64Data = this.getBase64FromServer();
    this.downloadFile(base64Data, this.data.fileName);
  },

  ///下载文件(逻辑代码)
  downloadFile(base64Str, fileName) {
    wx.showLoading({
      title: '下载中...'
    });
    downloadBase64File(base64Str, fileName)
      .then(savedFilePath => {
        console.log("缓存成功路径:" + savedFilePath)
        // 打开文件供用户保存
        wx.openDocument({
          filePath: savedFilePath,
          showMenu: true,
          success: () => {
            wx.showToast({
              title: '下载成功',
            })
          },
          fail: (err) => {
            wx.showToast({
              title: '打开文件失败',
              icon: 'none'
            });
            console.error(err);
          }
        });
        wx.hideLoading();
      })
      .catch(err => {
        wx.hideLoading();
        wx.showToast({
          title: '保存失败',
          icon: 'none'
        });
        console.error('下载错误:', err);
      });
  },

最后测试点击下载文件按钮可以预览文件

 

可以点击右上角三个点选择下载到手机上(可以手机的文件管理的文档中找到)