鸿蒙应用框架开发【选择并查看文档与媒体文件】 本地数据与文件

选择并查看文档与媒体文件

介绍

应用使用@ohos.file.picker、@ohos.file.fs等接口,实现了picker拉起文档编辑保存、拉起系统相册图片查看、拉起视频并播放的功能。

效果预览

1

使用说明:

  1. 在首页,应用显示查看最近打开文件功能的跳转按钮,点击后进入文件管理页面,可以通过最近页面,查看最近打开的文件。通过点击右上方的三个按钮,可以分别实现新建文档、选择图片或视频并打开预览、选择文档并打开的功能。
  2. 在查看文档界面,点击右上方左一按钮,可以实现当前文档另存为的功能;点击右上方中间的按钮,开启文档的编辑功能,textArea变成可编辑状态,用户输入数据后点击右上方第三个按钮,可以将当前文档内容进行保存操作(系统文档没有保存权限)。
  3. 在查看图片界面,picker拉起系统相册的图片,用户至多可选择三张图片查看,点击图片可以切换所显示的图片名及大小信息。
  4. 在查看视频界面,picker拉起系统相册的视频,用户至多可选择三个视频查看,点击视频播放并且可以显示的视频名及大小信息。

具体实现

  • 拉起picker选择文件、拉起picker保存文件、拉起picker选择图片或视频的功能封装在Index.ets,源码参考:[Index.ets]
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { router } from '@kit.ArkUI';
import { picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import Logger from '../common/Logger';
import MediaFileUri from '../media/MediaFileUri';
import { Constants } from '../common/Constants';

const MAX_SELECT_NUM = 3; // 选择媒体文件的最大数目
const TAG = 'pickerIndex';

@Entry
@Component
struct Index {
  @State uri: string = 'Hello World';
  @State filename: string = '';
  @State sizeFile: number = 0;
  @State log: string = '';
  @State imageFlagCur: number = 0;
  @StorageLink('fileSizeList') fileSizeList: Array<number> = [];
  @StorageLink('fileNameList') fileNameList: Array<string> = [];
  @StorageLink('fileUriList') fileUriList: Array<string> = [];
  @StorageLink('imageNames') imageNames: Array<string> = [];
  mediaFileUri: MediaFileUri = new MediaFileUri();
  scroller: Scroller = new Scroller();
  authorizeBundleName: string = 'com.open.file.uri.demo';

  // 拉起picker选择文件
  async callFilePickerSelectFile(): Promise<void> {
    try {
      let DocumentSelectOptions = new picker.DocumentSelectOptions();
      let documentPicker = new picker.DocumentViewPicker();
      documentPicker.select(DocumentSelectOptions).then((DocumentSelectResult) => {
        Logger.info(TAG,
          'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + JSON.stringify(DocumentSelectResult));
        let editFlag = false;
        if (DocumentSelectResult !== null && DocumentSelectResult !== undefined) {
          DocumentSelectResult.forEach((value) => {
            this.uri = value;
            editFlag = true;
            Logger.info(TAG, `select file uri: ${this.uri}`);
          })
        }
        if (editFlag) {
          this.getFilenameByUri(this.uri);
        }
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'DocumentViewPicker.select failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'DocumentViewPicker failed with err: ' + JSON.stringify(err));
    }
  }

  // 拉起picker保存文件
  async callFilePickerSaveFile(): Promise<void> {
    try {
      let DocumentSaveOptions = new picker.DocumentSaveOptions();
      DocumentSaveOptions.newFileNames = ['MyDocument_01.txt'];
      let documentPicker = new picker.DocumentViewPicker();
      documentPicker.save(DocumentSaveOptions).then((DocumentSaveResult) => {
        Logger.info(TAG,
          'DocumentViewPicker.save successfully, DocumentSaveResult uri: ' + JSON.stringify(DocumentSaveResult));
        if (DocumentSaveResult !== null && DocumentSaveResult !== undefined) {
          this.uri = DocumentSaveResult[0];
          Logger.info(TAG, `save file uri: ${this.uri}`);
        }
        this.getFilenameByUri(this.uri);
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'DocumentViewPicker.save failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'DocumentViewPicker failed with err: ' + err);
    }
  }

  async getFilenameByUriForMedia(myUris: string[]) {
    router.pushUrl({
      url: 'pages/ViewMedia',
      params: {
        uris: myUris
      }
    }, router.RouterMode.Standard);
  }

  async getFilenameByUri(myUri: string): Promise<void> {
    // 获取文件名称
    this.filename = (myUri.split('/').pop()) as string;
    router.pushUrl({
      url: 'pages/EditFile',
      params: {
        fileName: this.filename,
        myUri: myUri
      }
    }, router.RouterMode.Standard);
  }

  // 拉起picker选择图片/视频
  async callFilePickerSelectImage(): Promise<void> {
    let array: string[];
    try {
      // 设置photoPicker的参数
      let PhotoSelectOptions = new picker.PhotoSelectOptions();
      // 过滤选择媒体文件类型
      PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
      // 选择媒体文件的最大数目
      PhotoSelectOptions.maxSelectNumber = MAX_SELECT_NUM;
      let mediaFlag = false;
      // 使用图库选择器对象前,需要先创建PhotoViewPicker实例
      let photoPicker = new picker.PhotoViewPicker();
      photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult) => {
        // 日志中记录成功信息
        Logger.info(TAG,
          'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult));
        // 接口采用callback异步返回形式,返回PhotoSelectResult对象,故进行下一步操作前要先判断是否已经成功返回PhotoSelectResult对象了
        if (PhotoSelectResult !== null && PhotoSelectResult !== undefined) {
          // PhotoSelectResult为返回的结果集。
          // 其中包含Array<string>类型的photoUris,为返回图库选择后的媒体文件的uri数组;还包含boolean类型的isOriginalPhoto,指示返回图库选择后的媒体文件是否为原图。
          // 声明变量array,其取值为PhotoSelectResult中的数组。
          array = PhotoSelectResult['photoUris'];
          array.forEach((value) => {
            this.uri = value;
            mediaFlag = true;
            Logger.info(TAG, `select image/video uri: ${this.uri}`);
          })
        }
        if (mediaFlag) {
          this.getFilenameByUriForMedia(array);
        }
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'PhotoViewPicker.select failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'PhotoViewPicker failed with err: ' + err);
    }
  }

  aboutToDisappear(): void {
    this.fileNameList = [];
    this.fileSizeList = [];
    this.fileUriList = [];
  }

  onPageShow(): void {
    this.mediaFileUri.getAllFiles();
  }

  build() {
    Scroll(this.scroller) {
      Row() {
        Column() {
          Row() {
            Column() {
              Text($r('app.string.last_open'))
                .fontFamily('HarmonyHeiTi-Bold')
                .fontSize($r('app.float.text_font_size_30'))
                .fontWeight(Constants.TEXT_FONT_WIGHT)
                .textAlign(TextAlign.Start)
                .fontColor($r('app.color.text_font_color'))
                .lineHeight($r('app.float.first_line_height'))
                .width(Constants.SEVENTY_PERCENT)
                .height($r('app.float.first_line_height'))
            }
            .width(Constants.FIFTY_PERCENT)
            .margin({ left: Constants.PADDING_LEFT_RIGHT })
            .alignItems(HorizontalAlign.Start)

            Row() {
              Image($r('app.media.ic_saveas'))
                .width($r('app.float.image_size'))
                .height($r('app.float.image_size'))
                .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
                .id('newFile')
                .onClick(() => {
                  this.callFilePickerSaveFile();
                })

              Image($r('app.media.ic_picture'))
                .width($r('app.float.image_size'))
                .height($r('app.float.image_size'))
                .id('picture')
                .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
                .onClick(() => {
                  this.callFilePickerSelectImage();
                })

              Image($r('app.media.ic_folder'))
                .width($r('app.float.image_size'))
                .height($r('app.float.image_size'))
                .id('folder')
                .opacity(1)
                .margin({ right: Constants.MARGIN_RIGHT })
                .onClick(() => {
                  this.callFilePickerSelectFile();
                })
            }
            .justifyContent(FlexAlign.End)
            .padding({ right: Constants.PADDING_RIGHT })
            .width(Constants.FIFTY_PERCENT)
          }
          // 第一行结束
          .width(Constants.FULL_PERCENT)
          .height($r('app.float.first_line_height'))
          .margin({
            top: $r('app.float.first_line_margin_top'),
            left: $r('app.float.first_line_margin_left'),
            right: $r('app.float.first_line_margin_right'),
            bottom: $r('app.float.first_line_margin_bottom')
          })

          Row() {
            Text($r('app.string.view_last_open'))
              .fontSize($r('app.float.text_area_font_size'))
              .textAlign(TextAlign.Start)
              .lineHeight($r('app.float.line_height'))
              .margin({ left: $r('app.float.image_margin_left') })

            Blank()

            Image($r('app.media.right_arrow'))
              .height($r('app.float.text_height_19'))
              .width($r('app.float.image_width'))
              .margin({
                left: $r('app.float.image_margin_left'),
                right: $r('app.float.image_margin_left'),
                top: $r('app.float.image_margin_top'),
                bottom: $r('app.float.image_margin_top')
              })
          }
          .backgroundColor($r('app.color.start_window_background'))
          .width(Constants.FULL_PERCENT)
          .height($r('app.float.row_height'))
          .padding({
            top: $r('app.float.row_padding'),
            left: $r('app.float.margin_padding_12'),
            right: $r('app.float.margin_padding_12')
          })
          .onClick(() => {
            this.callFilePickerSelectFile();
          })

          Column() {
            List({ space: Constants.LIST_SPACE, initialIndex: 0 }) {
              ForEach(this.fileNameList, (item: string, index?: number) => {
                ListItem() {
                  Row() {
                    Image($r('app.media.ic_docs'))
                      .width(Constants.IMAGE_WIDTH)
                      .height($r('app.float.line_height'))
                      .margin({
                        left: $r('app.float.margin_left'),
                        right: $r('app.float.margin_right')
                      })

                    Text(item)
                      .fontSize($r('app.float.text_area_font_size'))
                      .fontFamily('HarmonyHeiTi-Medium')
                      .fontColor($r('app.color.text_font_color'))
                      .lineHeight($r('app.float.line_height'))
                      .textAlign(TextAlign.Start)
                      .margin({ right: $r('app.float.padding_left_right') })
                      .width(Constants.SIXTY_FOUR_PERCENT)
                    if (index !== undefined) {
                      Text('Size: ' + JSON.stringify(this.fileSizeList[index]) + 'B')
                        .fontSize($r('app.float.text_font_size_14'))
                        .fontFamily('HarmonyHeiTi-Medium')
                        .lineHeight($r('app.float.text_height_19'))
                        .fontColor($r('app.color.text_font_color'))
                        .textAlign(TextAlign.End)
                        .opacity(Constants.TEXT_OPACITY)
                        .width(Constants.TEXT_WIDTH)
                        .margin({ right: $r('app.float.margin_padding_12') })
                    }
                  }
                  .id('fileItem' + (index !== undefined ? index : ""))
                  .borderRadius(Constants.BORDER_RADIUS)
                  .width(Constants.FULL_PERCENT)
                  .height($r('app.float.row_height_64'))
                  .padding({ right: $r('app.float.margin_padding_12') })
                  .backgroundColor($r('app.color.start_window_background'))
                }
                .onClick(() => {
                  Logger.info(TAG, 'fileAsset.displayName fileName item: ' + item);
                  if (index !== undefined) {
                    router.pushUrl({
                      url: 'pages/EditFile',
                      params: {
                        fileName: item,
                        myUri: this.fileUriList[index]
                      }
                    }, router.RouterMode.Standard);
                  }
                })
              }, (item: string) => item)
            }
            .listDirection(Axis.Vertical) // 排列方向
            .id('indexList')
            .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
            .scrollBar(BarState.Auto)
            .alignListItem(ListItemAlign.Center)
            .margin({
              top: Constants.LIST_MARGIN_TOP,
              left: $r('app.float.margin_padding_12'),
              right: $r('app.float.margin_padding_12')
            })
          }
          .height(Constants.FULL_PERCENT)
          .width(Constants.FULL_PERCENT)
        }
        .alignItems(HorizontalAlign.Center)
        .width(Constants.FULL_PERCENT)
        .height(Constants.FULL_PERCENT)
        .backgroundColor($r('app.color.common_background'))
      }
      .height(Constants.FULL_PERCENT)
    }
  }
}
  • 使用new picker.DocumentViewPicker来创建文件picker实例,使用documentPicker.select来拉起picker选择文件,使用documentPicker.save来拉起picker保存文件,接口参考:@ohos.file.picker

  • 使用new picker.PhotoViewPicker来创建图库picker实例,使用photoPicker.select来拉起picker选择图片或视频,接口参考:@ohos.file.picker

  • 编辑文件并保存的功能封装在EditFile.ets,源码参考:[EditFile.ets]

/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { promptAction, router } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { fileIo, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import MediaFileUri from '../media/MediaFileUri';
import Logger from '../common/Logger';
import { terminateSelf } from '../utils/utils';
import { Constants } from '../common/Constants';

const TAG = 'EditFile: ';
let storage = LocalStorage.getShared();
const OPACITY_VALUE = 0.6; // 透明度

interface myParams extends Object {
  myUri: string,
  fileName: string
};

@Entry(storage)
@Component
struct EditFile {
  @LocalStorageLink('loadFlag') loadFlag: Boolean = false;
  @LocalStorageLink('loadFileSize') loadFileSize: number = 0;
  @LocalStorageLink('loadFileName') loadFileName: string = '';
  @LocalStorageLink('loadFileContent') loadFileContent: string = '';
  @LocalStorageLink('loadUri') loadUri: string = '';
  @LocalStorageLink('fd') loadFd: number = 0;
  @StorageLink('editable') editable: Boolean = false;
  @StorageLink('myFileSize') myFileSize: number = 0;
  @StorageLink('myFileContent') myFileContent: string = '';
  @State myContext: Context = getContext(this) as common.UIAbilityContext;
  @State myUri: string = '';
  @State opacityValue: number = OPACITY_VALUE;
  @State uriSave: string = '';
  @State myFileName: string = '';
  public fileContentFlag: boolean = false;
  newFileContent: string = '';
  scroller: Scroller = new Scroller();
  controller: TextAreaController = new TextAreaController();
  mediaFileUri: MediaFileUri = new MediaFileUri();

  getFileInfo(): void {
    if (this.loadFlag) {
      this.myFileName = this.loadFileName;
      this.myFileContent = this.loadFileContent;
      this.myFileSize = this.loadFileSize;
      this.myUri = this.loadUri;
      Logger.info(TAG, 'The count of getFileInfo is myFileContent ' + this.myFileContent);
    } else {
      this.myUri = (router.getParams() as myParams).myUri;
      this.myFileName = (router.getParams() as myParams).fileName;
      this.myFileContent = this.mediaFileUri.readFileContent(this.myUri);
      this.myFileSize = this.mediaFileUri.myGetFileSize(this.myUri, fileIo.OpenMode.READ_ONLY);
      Logger.info(TAG, 'The count of getFileInfo is myFileName is: ' + this.myFileName);
      Logger.info(TAG, 'The count of getFileInfo is myFileContent ' + this.myFileContent);
      Logger.info(TAG, 'The count of getFileInfo is myFileSize ' + this.myFileSize);
    }
    AppStorage.setOrCreate('myFileContent', this.myFileContent);
    AppStorage.setOrCreate('myFileSize', this.myFileSize);
  }

  async writeContentForSaveAsFile(myUri: string, wrFlag: Boolean = false): Promise<void> {
    if (wrFlag) {
      Logger.info(TAG, 'fileAsset.displayName wrFlag is true');
      Logger.info(TAG, 'fileAsset.displayName wrFlag myFileContent :' + this.myFileContent);
      this.mediaFileUri.writeFileContent(myUri, this.myFileContent);
    }
  }

  // 拉起picker保存文件
  async callFilePickerSaveFile(): Promise<void> {
    try {
      let DocumentSaveOptions = new picker.DocumentSaveOptions();
      DocumentSaveOptions.newFileNames = ['MyDocument_01.txt'];
      let documentPicker = new picker.DocumentViewPicker();
      documentPicker.save(DocumentSaveOptions).then((DocumentSaveResult) => {
        Logger.info(TAG,
          'DocumentViewPicker.save successfully, DocumentSaveResult uri: ' + JSON.stringify(DocumentSaveResult));
        if (DocumentSaveResult !== null && DocumentSaveResult !== undefined) {
          this.uriSave = DocumentSaveResult[0];
          Logger.info(TAG, `save callFilePickerSaveFile file this.uriSave: ${this.uriSave}`);
        }
        Logger.info(TAG, 'fileAsset.displayName wrFlag myFileContent :' + this.myFileContent);
        // 用 medialibrary 重新获取uri,进行写入操作
        this.writeContentForSaveAsFile(this.uriSave, true);
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'DocumentViewPicker.save failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'DocumentViewPicker failed with err: ' + err);
    }
  }

  onPageShow(): void {
    this.getFileInfo();
    this.editable = false;
  }

  build() {
    Column() {
      // 顶部的行容器
      Row() {
        // 后退箭头
        Row() {
          Image($r('app.media.ic_back'))
            .focusable(true)
            .focusOnTouch(true)
            .id('backIndex')
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .align(Alignment.Start)
            .onClick(() => {
              if (this.loadFlag) {
                Logger.info(TAG, 'end page');
                let context = getContext(this);
                terminateSelf(context);
              } else {
                router.back();
              }
            })
        }
        .margin({ left: Constants.MARGIN_LEFT })

        // 文件名及信息
        Column() {
          Row() {
            Text(this.myFileName)
              .focusable(true)
              .focusOnTouch(true)
              .fontSize($r('app.float.text_font_size'))
              .fontFamily('HarmonyHeiTi-Bold')
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .fontWeight(Constants.TEXT_FONT_WIGHT)
              .lineHeight(Constants.TEXT_LINE_HEIGHT)
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }
          .width(Constants.FULL_PERCENT)
          .align(Alignment.Start)
          .margin({
            left: Constants.MARGIN_LEFT,
            top: Constants.MARGIN_TOP,
            bottom: Constants.MARGIN_ZERO_POINT_THREE_PERCENT
          })

          Row() {
            Text('size: ' + JSON.stringify(this.myFileSize) + 'B')
              .focusable(true)
              .focusOnTouch(true)
              .opacity(Constants.TEXT_OPACITY)
              .fontFamily('HarmonyHeiTi')
              .fontSize($r('app.float.text_font_size_14'))
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .lineHeight(Constants.TEXT_LINE_HEIGHT_19)
              .fontWeight(Constants.TEXT_FONT_WIGHT_400)
          }
          .width(Constants.FULL_PERCENT)
          .margin({
            left: Constants.MARGIN_LEFT,
            top: Constants.MARGIN_ZERO_POINT_THREE_PERCENT,
            bottom: Constants.MARGIN_ZERO_POINT_FIVE_PERCENT
          })
          .align(Alignment.Start)
        }
        .width(Constants.FORTY_FIVE_PERCENT)
        .margin({ left: Constants.MARGIN_LEFT })

        // 右边三个图标
        Row() {
          Image($r('app.media.ic_saveas'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .id('saveAs')
            .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
            .onClick(() => {
              this.callFilePickerSaveFile();
            })
            .visibility(this.loadFlag ? Visibility.Hidden : Visibility.Visible)

          Image($r('app.media.ic_writting'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .id('editable')
            .margin({ right: Constants.IMAGE_MARGIN_RIGHT })
            .onClick(() => {
              this.editable = true;
              AppStorage.setOrCreate('editable', this.editable);
              Logger.info(TAG, 'EditFile caretPosition length = ' + this.myFileContent.length);
              this.controller.caretPosition(this.myFileContent.length);
              promptAction.showToast({ message: $r('app.string.editable') });
            })

          Image($r('app.media.ic_save'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .id('save')
            .margin({ right: Constants.MARGIN_LEFT })
            .onClick(() => {
              if (this.fileContentFlag) {
                let flage: boolean = true;
                this.myFileContent = this.newFileContent;
                AppStorage.setOrCreate('myFileContent', this.myFileContent);
                Logger.info(TAG, 'save onClick myFileContent is: ' + this.myFileContent);
                Logger.info(TAG, 'save onClick this.loadUri: ' + this.loadUri);
                if (this.loadFlag) {
                  let file = fileIo.openSync(this.loadUri,
                    fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.TRUNC);
                  Logger.info(TAG, 'save onClick file.fd is: ' + file.fd);
                  fileIo.write(file.fd, this.myFileContent).then((writeLen) => {
                    Logger.info(TAG, 'write data to file succeed and size is:' + writeLen);
                    this.myFileSize = fileIo.statSync(file.fd).size;
                    AppStorage.setOrCreate('myFileSize', this.myFileSize);
                    Logger.info(TAG, 'save onClick this.myFileSize ' + this.myFileSize);
                  }).catch((err: BusinessError) => {
                    Logger.info(TAG, 'write data to file failed with error:' + JSON.stringify(err));
                  });
                  fileIo.closeSync(file);
                } else {
                  try {
                    let file = fileIo.openSync(this.myUri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.TRUNC);
                    let writeLen = fileIo.writeSync(file.fd, this.myFileContent);
                    this.myFileSize = fileIo.statSync(file.fd).size;
                    AppStorage.setOrCreate('myFileSize', this.myFileSize);
                    Logger.info(TAG, 'write data to file succeed and size is:' + writeLen);
                    fileIo.closeSync(file);
                  } catch (err) {
                    flage = false;
                    Logger.info(`save data to file failed with error:
                      ${JSON.stringify(err)}: ${JSON.stringify(err?.message)}`);
                    promptAction.showToast({
                      message: Constants.SHOW_TOAST_MESSAGE,
                      duration: 6500
                    })
                  }
                }
                if (flage) {
                  this.editable = false;
                  AppStorage.setOrCreate('editable', this.editable);
                  promptAction.showToast({ message: $r('app.string.saved') });
                }
              }
            })
        }
        .height(Constants.FIFTY_PERCENT)
        .width(Constants.THIRTY_SEVEN_POINT_TWO)
        .padding({ right: Constants.MARGIN_ZERO_POINT_FIVE_PERCENT })
        .justifyContent(FlexAlign.End)
      }
      .height(Constants.SEVEN_POINT_FOUR)
      .width(Constants.FULL_PERCENT)

      Scroll(this.scroller) {
        // TextArea的行容器
        Row() {
          TextArea({
            text: this.newFileContent ? this.newFileContent : this.myFileContent,
            placeholder: Constants.TEXT_AREA_PLACEHOLDER,
            controller: this.controller
          })
            .id('textArea')
            .fontSize($r('app.float.text_area_font_size'))
            .fontColor($r('app.color.text_font_color'))
            .opacity(this.opacityValue)
            .fontWeight(Constants.TEXT_FONT_WIGHT_400)
            .align(Alignment.TopStart)
            .textAlign(TextAlign.Start)
            .backgroundColor($r('app.color.common_background'))
            .fontFamily('HarmonyHeiTi')
            .padding({
              top: $r('app.float.padding_top_bottom'),
              right: $r('app.float.padding_left_right'),
              left: $r('app.float.padding_left_right'),
              bottom: $r('app.float.padding_top_bottom')
            })
            .focusable(this.editable ? true : false)
            .focusOnTouch(true)
            .defaultFocus(false)
            .onFocus(() => {
              this.opacityValue = 1;
            })
            .onBlur(() => {
              this.opacityValue = OPACITY_VALUE;
            })
            .onChange((value: string) => {
              this.newFileContent = value;
              this.fileContentFlag = true;
            })
        }
        .padding({
          top: Constants.PADDING_TOP,
          left: Constants.PADDING_LEFT_RIGHT,
          right: Constants.PADDING_LEFT_RIGHT
        })
      }
    }
    .backgroundColor($r('app.color.common_background'))
    .height(Constants.FULL_PERCENT)
  }
}
  • 使用fs.openSync、fs.writeSync、fs.readSync、fs.closeSync分别用来打开文件、写文件、读文件、关闭文件,接口参考:@ohos.file.fs

  • 拉起图片或视频并查看的功能封装在ViewMedia.ets,源码参考:[ViewMedia.ets]

/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { router } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { fileIo, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import MediaFileUri from '../media/MediaFileUri';
import Logger from '../common/Logger';
import { Constants } from '../common/Constants';

const TAG = 'ViewMedia';

interface myParams extends Object {
  uris: string[]
};

@Entry
@Component
struct ViewMedia {
  @State myContext: Context = getContext(this) as common.UIAbilityContext;
  @State myFileSizes: number[] = [];
  @State myFileNames: string[] = [];
  @State myFileTypes: number[] = [];
  @StorageLink('myFileName') myFileName: string = '';
  @StorageLink('myFileSize') myFileSize: number = 0;
  @State myUris: string[] = (router.getParams() as myParams).uris;
  @State uri: string = 'Hello World';
  @StorageLink('showPauses') showPauses: Array<number> = [];
  mediaFileUri: MediaFileUri = new MediaFileUri();
  scroller: Scroller = new Scroller();
  currentUri: string = '';
  controllers: Array<VideoController> = [];

  // 拉起picker保存图片/视频
  async callFilePickerSaveImageVideo(): Promise<void> {
    try {
      let PhotoSaveOptions = new picker.PhotoSaveOptions();
      PhotoSaveOptions.newFileNames = ['PhotoViewPicker01.jpg', 'PhotoViewPicker01.mp4'];
      let photoPicker = new picker.PhotoViewPicker();
      photoPicker.save(PhotoSaveOptions).then((PhotoSaveResult) => {
        Logger.info(TAG, 'PhotoViewPicker.save successfully, PhotoSaveResult uri: ' + JSON.stringify(PhotoSaveResult));
        if (PhotoSaveResult !== null && PhotoSaveResult !== undefined) {
          PhotoSaveResult.forEach((value: string) => {
            this.uri = value
            Logger.info(TAG, `save image/video uri: ${this.uri}`);
          })
        }
      }).catch((err: BusinessError) => {
        Logger.error(TAG, 'PhotoViewPicker.save failed with err: ' + JSON.stringify(err));
      });
    } catch (err) {
      Logger.error(TAG, 'PhotoViewPicker failed with err: ' + err);
    }
  }

  onPageShow() {
    this.getImagesInfo();
    this.myFileName = this.myFileNames[0];
    this.myFileSize = this.myFileSizes[0];
    Logger.info(TAG, 'onPageShow getFilenameByUriForMedia this.myFileName ' + this.myFileName);
    Logger.info(TAG, 'onPageShow getFilenameByUriForMedia begin ' + this.myFileSize);
    AppStorage.setOrCreate('myFileName', this.myFileName);
    AppStorage.setOrCreate('myFileSize', this.myFileSize);
  }

  async getMediaNameByUri(myUri: string, index: number) {
    Logger.info(TAG, 'getMediaNameByUri getFilenameByUriForMedia begin');
    this.myFileName = (myUri.split('/').pop()) as string;
    this.myFileNames[index] = this.myFileName;
  }

  getImagesInfo() {
    for (let index = 0; index < this.myUris.length; index++) {
      Logger.info(TAG, 'getFilenameByUriForMedia  getImagesInfo  index: ' + index);
      this.controllers[index] = new VideoController();
      this.getMediaNameByUri(this.myUris[index], index);
      this.myFileSizes[index] = this.mediaFileUri.myGetFileSize(this.myUris[index], fileIo.OpenMode.READ_ONLY);
      Logger.info(TAG, 'getFilenameByUriForMedia  getVideosInfo  this.myFileNames[index]: '
        + this.myFileNames[index] + ' index ' + index);
      Logger.info(TAG, 'getFilenameByUriForMedia getVideosInfo this.myFileSizes[index]' + this.myFileSizes[index]);
      Logger.info(TAG, 'getFilenameByUriForMedia getVideosInfo this.myFileTypes[index] cc' + this.myFileTypes[index]);
    }
  }

  build() {
    Column() {
      // 顶部的行容器
      Row() {
        // 后退箭头
        Row() {
          Image($r('app.media.ic_back'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .align(Alignment.Start)
            .id('back2Index')
            .onClick(() => {
              router.back();
            })
        }
        .width(Constants.BACK_WIDTH)
        .padding({ left: Constants.BACK_PADDING_LEFT })

        // 文件名及信息
        Column() {
          Row() {
            Text(this.myFileName)
              .focusable(true)
              .focusOnTouch(true)
              .fontSize($r('app.float.text_font_size'))
              .fontFamily('HarmonyHeiTi-Bold')
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .fontWeight(Constants.TEXT_FONT_WIGHT)
              .lineHeight($r('app.float.text_height'))
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }
          .width(Constants.FULL_PERCENT)
          .align(Alignment.Start)
          .margin({
            top: Constants.MARGIN_TOP,
            bottom: Constants.MARGIN_ZERO_POINT_THREE_PERCENT
          })

          Row() {
            Text('size: ' + JSON.stringify(this.myFileSize) + 'B')
              .focusable(true)
              .focusOnTouch(true)
              .opacity(Constants.TEXT_OPACITY)
              .fontFamily('HarmonyHeiTi')
              .fontSize($r('app.float.text_font_size_14'))
              .fontColor($r('app.color.text_font_color'))
              .textAlign(TextAlign.Start)
              .lineHeight($r('app.float.text_height_19'))
              .fontWeight(Constants.TEXT_FONT_WIGHT_400)
          }
          .width(Constants.FULL_PERCENT)
          .margin({
            top: Constants.MARGIN_ZERO_POINT_THREE_PERCENT,
            bottom: Constants.MARGIN_ZERO_POINT_FIVE_PERCENT
          })
          .align(Alignment.Start)
        }
        .width(Constants.FORTY_FIVE_PERCENT)
        .margin({ left: Constants.MARGIN_LEFT })

        // 右边一个图标,另存为
        Row() {
          Image($r('app.media.ic_saveas'))
            .focusable(true)
            .focusOnTouch(true)
            .width($r('app.float.image_size'))
            .height($r('app.float.image_size'))
            .visibility(Visibility.Hidden)
        }
        .height(Constants.FULL_PERCENT)
        .width(Constants.THIRTY_SEVEN_POINT_TWO)
        .padding({ right: Constants.BACK_PADDING_LEFT })
        .justifyContent(FlexAlign.End)
      }
      .height(Constants.SEVEN_POINT_FOUR)
      .width(Constants.FULL_PERCENT)

      Scroll(this.scroller) {
        // 显示媒体文件的容器
        Column() {
          List({ space: Constants.LIST_SPACE_20, initialIndex: 0 }) {
            ForEach(this.myUris, (uri: string, index?: number) => {
              ListItem() {
                Column() {
                  Image(uri)
                    .borderRadius(Constants.BORDER_RADIUS)
                    .onClick(() => {
                      if (index !== undefined) {
                        this.myFileSize = this.myFileSizes[index];
                        this.myFileName = this.myFileNames[index];
                      }
                      AppStorage.setOrCreate('myFileName', this.myFileName);
                      AppStorage.setOrCreate('myFileSize', this.myFileSize);
                      Logger.info(TAG, 'Image onClick myFileName is ' + this.myFileName);
                      Logger.info(TAG, 'Image onClick myFileName is ' + this.myFileSize);
                    })
                  if (index !== undefined) {
                    Stack({ alignContent: Alignment.Center }) {
                      Video({
                        src: uri,
                        controller: this.controllers[index]
                      })
                        .autoPlay(false)
                        .controls(true)
                        .borderRadius(Constants.BORDER_RADIUS)

                      Image($r('app.media.ic_PAUSE'))
                        .width($r('app.float.image_size'))
                        .height($r('app.float.image_size'))
                        .onClick(() => {
                          this.controllers[index].start();
                          this.showPauses[index] = 0;
                        })
                    }
                    .onClick(() => {
                      this.myFileSize = this.myFileSizes[index];
                      this.myFileName = this.myFileNames[index];

                      AppStorage.setOrCreate('myFileName', this.myFileName);
                      AppStorage.setOrCreate('myFileSize', this.myFileSize);
                    })
                  }
                }
                .height(Constants.FULL_PERCENT)
              }
              .height(Constants.TWENTY_FIVE_PERCENT)
            }, (item: string) => item)
          }
          .id('picScroller')
          .scrollBar(BarState.Auto)
        }
      }
      .padding({
        top: Constants.ONE_POINT_FIVE_PERCENT,
        left: Constants.PADDING_LEFT_RIGHT,
        right: Constants.PADDING_LEFT_RIGHT
      })
    }
    .backgroundColor($r('app.color.common_background'))
    .height(Constants.FULL_PERCENT)
  }
}

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值