当前位置: 首页 > news >正文

Chromium 中JavaScript File API接口c++代码实现

构造函数File - Web API | MDN (mozilla.org)构造函数

File()

返回一个新构建的 File 对象。

实例属性

File 接口还继承了 Blob 接口的属性。

File.lastModified 只读

返回文件的最后修改时间,以 UNIX 纪元(1970 年 1 月 1 日午夜)以来的毫秒为单位。

File.lastModifiedDate 已弃用 只读 非标准

返回 File 对象引用的文件的最后修改时间的 Date。

File.name 只读

返回 File 对象引用的文件的名称。

File.webkitRelativePath 只读

返回 File 对象相对于 URL 的路径。

实例方法

File 接口还继承了 Blob 接口的方法。

一、前端测试用例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test File api</title>
</head>
<body>
<input type="file" id="filepicker" multiple />
<div><p>选定文件列表:</p><ul id="output"></ul>
</div><script>
const output = document.getElementById("output");
const filepicker = document.getElementById("filepicker");filepicker.addEventListener("change", (event) => {const files = event.target.files;output.textContent = "";for (const file of files) {const li = document.createElement("li");li.textContent = file.name;output.appendChild(li);}
});</script>
</body>
</html>

二、c++代码中file api定义和实现

前端中

File.lastModified 
File.lastModifiedDate 
File.name
File.webkitRelativePath定义均在file.idl文件中。

1、定义third_party\blink\renderer\core\fileapi\file.idl

/** Copyright (C) 2008 Apple Inc. All Rights Reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions* are met:* 1. Redistributions of source code must retain the above copyright*    notice, this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright*    notice, this list of conditions and the following disclaimer in the*    documentation and/or other materials provided with the distribution.** THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/// https://w3c.github.io/FileAPI/#file-section[Exposed=(Window,Worker),Serializable
] interface File : Blob {[CallWith=ExecutionContext] constructor(sequence<BlobPart> fileBits, USVString fileName, optional FilePropertyBag options = {});readonly attribute DOMString name;readonly attribute long long lastModified;// Non-standard APIs[MeasureAs=FileGetLastModifiedDate, CallWith=ScriptState] readonly attribute object lastModifiedDate;[MeasureAs=PrefixedFileRelativePath] readonly attribute DOMString webkitRelativePath;
};

2、file.idl接口实现

third_party\blink\renderer\core\fileapi\file.h

third_party\blink\renderer\core\fileapi\file.cc

/** Copyright (C) 2008 Apple Inc. All Rights Reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions* are met:* 1. Redistributions of source code must retain the above copyright*    notice, this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright*    notice, this list of conditions and the following disclaimer in the*    documentation and/or other materials provided with the distribution.** THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_H_#include "base/dcheck_is_on.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"namespace blink {class FilePropertyBag;
class FileMetadata;
class FormControlState;
class KURL;
class ExecutionContext;class CORE_EXPORT File final : public Blob {DEFINE_WRAPPERTYPEINFO();public:// AllContentTypes should only be used when the full path/name are trusted;// otherwise, it could allow arbitrary pages to determine what applications an// user has installed.enum ContentTypeLookupPolicy {kWellKnownContentTypes,kAllContentTypes,};// The user should not be able to browse to some files, such as the ones// generated by the Filesystem API.enum UserVisibility { kIsUserVisible, kIsNotUserVisible };// Constructor in File.idlstatic File* Create(ExecutionContext*,const HeapVector<Member<V8BlobPart>>& file_bits,const String& file_name,const FilePropertyBag* options);// For deserialization.static File* CreateFromSerialization(const String& path,const String& name,const String& relative_path,UserVisibility user_visibility,bool has_snapshot_data,uint64_t size,const absl::optional<base::Time>& last_modified,scoped_refptr<BlobDataHandle> blob_data_handle) {return MakeGarbageCollected<File>(path, name, relative_path, user_visibility, has_snapshot_data, size,last_modified, std::move(blob_data_handle));}static File* CreateFromIndexedSerialization(const String& name,uint64_t size,const absl::optional<base::Time>& last_modified,scoped_refptr<BlobDataHandle> blob_data_handle) {return MakeGarbageCollected<File>(String(), name, String(), kIsNotUserVisible, true, size, last_modified,std::move(blob_data_handle));}// For session restore feature.// See also AppendToControlState().static File* CreateFromControlState(ExecutionContext* context,const FormControlState& state,wtf_size_t& index);static String PathFromControlState(const FormControlState& state,wtf_size_t& index);static File* CreateWithRelativePath(ExecutionContext* context,const String& path,const String& relative_path);// If filesystem files live in the remote filesystem, the port might pass the// valid metadata (whose length field is non-negative) and cache in the File// object.//// Otherwise calling size(), lastModifiedTime() and slice() will synchronously// query the file metadata.static File* CreateForFileSystemFile(ExecutionContext* context,const String& name,const FileMetadata& metadata,UserVisibility user_visibility) {return MakeGarbageCollected<File>(context, name, metadata, user_visibility);}// KURL has a String() operator, so if this signature is called and not// deleted it will overload to the signature above// `CreateForFileSystemFile(String, FileMetadata, user_visibility)`.static File* CreateForFileSystemFile(const KURL& url,const FileMetadata& metadata,UserVisibility user_visibility) = delete;static File* CreateForFileSystemFile(const KURL& url,const FileMetadata& metadata,UserVisibility user_visibility,scoped_refptr<BlobDataHandle> blob_data_handle) {return MakeGarbageCollected<File>(url, metadata, user_visibility,std::move(blob_data_handle));}// Calls RegisterBlob through the relevant FileSystemManager, then constructs// a File with the resulting BlobDataHandle.static File* CreateForFileSystemFile(ExecutionContext& context,const KURL& url,const FileMetadata& metadata,UserVisibility user_visibility);File(ExecutionContext* context,const String& path,ContentTypeLookupPolicy = kWellKnownContentTypes,UserVisibility = File::kIsUserVisible);File(ExecutionContext* context,const String& path,const String& name,ContentTypeLookupPolicy,UserVisibility);File(const String& path,const String& name,const String& relative_path,UserVisibility,bool has_snapshot_data,uint64_t size,const absl::optional<base::Time>& last_modified,scoped_refptr<BlobDataHandle>);File(const String& name,const absl::optional<base::Time>& modification_time,scoped_refptr<BlobDataHandle>);File(ExecutionContext* context,const String& name,const FileMetadata& metadata,UserVisibility user_visibility);File(const KURL& file_system_url,const FileMetadata& metadata,UserVisibility user_visibility,scoped_refptr<BlobDataHandle> blob_data_handle);File(const File&);KURL FileSystemURL() const {
#if DCHECK_IS_ON()DCHECK(HasValidFileSystemURL());
#endifreturn file_system_url_;}// Create a file with a name exposed to the author (via File.name and// associated DOM properties) that differs from the one provided in the path.static File* CreateForUserProvidedFile(ExecutionContext* context,const String& path,const String& display_name) {if (display_name.empty()) {return MakeGarbageCollected<File>(context, path, File::kAllContentTypes,File::kIsUserVisible);}return MakeGarbageCollected<File>(context, path, display_name,File::kAllContentTypes,File::kIsUserVisible);}static File* CreateForFileSystemFile(const String& path,const String& name,ContentTypeLookupPolicy policy = kWellKnownContentTypes) {if (name.empty()) {return MakeGarbageCollected<File>(/*context=*/nullptr, path, policy,File::kIsNotUserVisible);}return MakeGarbageCollected<File>(/*context=*/nullptr, path, name, policy,File::kIsNotUserVisible);}File* Clone(const String& name = String()) const;// This method calls CaptureSnapshotIfNeeded, and thus can involve synchronous// IPC and file operations.uint64_t size() const override;bool IsFile() const override { return true; }bool HasBackingFile() const override { return has_backing_file_; }const String& GetPath() const {
#if DCHECK_IS_ON()DCHECK(HasValidFilePath());
#endifreturn path_;}const String& name() const { return name_; }// Getter for the lastModified IDL attribute,// http://dev.w3.org/2006/webapi/FileAPI/#file-attrs// This method calls CaptureSnapshotIfNeeded, and thus can involve synchronous// IPC and file operations.int64_t lastModified() const;// Getter for the lastModifiedDate IDL attribute,// http://www.w3.org/TR/FileAPI/#dfn-lastModifiedDate// This method calls CaptureSnapshotIfNeeded, and thus can involve synchronous// IPC and file operations.ScriptValue lastModifiedDate(ScriptState* script_state) const;// Returns File's last modified time.// If the modification time isn't known, the current time is returned.// This method calls CaptureSnapshotIfNeeded, and thus can involve synchronous// IPC and file operations.base::Time LastModifiedTime() const;// Similar to |LastModifiedTime()|, except this returns absl::nullopt rather// than the current time if the modified time is unknown.// This is used by SerializedScriptValue to serialize the last modified time// of a File object.// This method calls CaptureSnapshotIfNeeded, and thus can involve synchronous// IPC and file operations.absl::optional<base::Time> LastModifiedTimeForSerialization() const;UserVisibility GetUserVisibility() const { return user_visibility_; }// Returns the relative path of this file in the context of a directory// selection.const String& webkitRelativePath() const { return relative_path_; }// Returns true if this has a valid snapshot metadata// (i.e. snapshot_size_.has_value()).bool HasValidSnapshotMetadata() const { return snapshot_size_.has_value(); }// Returns true if the sources (file path, file system URL, or blob handler)// of the file objects are same or not.bool HasSameSource(const File& other) const;// Return false if this File instance is not serializable to FormControlState.bool AppendToControlState(FormControlState& state);private:// Note that this involves synchronous file operation. Think twice before// calling this function.void CaptureSnapshotIfNeeded() const;#if DCHECK_IS_ON()// Instances backed by a file must have an empty file system URL.bool HasValidFileSystemURL() const {return !HasBackingFile() || file_system_url_.IsEmpty();}// Instances not backed by a file must have an empty path set.bool HasValidFilePath() const { return HasBackingFile() || path_.empty(); }
#endifbool has_backing_file_;UserVisibility user_visibility_;String path_;String name_;KURL file_system_url_;// If snapshot_size_ has no value, the snapshot metadata is invalid and// we retrieve the latest metadata synchronously in size(),// LastModifiedTime() and slice().// Otherwise, the snapshot metadata are used directly in those methods.mutable absl::optional<uint64_t> snapshot_size_;mutable absl::optional<base::Time> snapshot_modification_time_;String relative_path_;
};template <>
struct DowncastTraits<File> {static bool AllowFrom(const Blob& blob) { return blob.IsFile(); }
};}  // namespace blink#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_H_

3、File 接口继承了 Blob 接口的属性 定义

     third_party\blink\renderer\core\fileapi\blob.idl

     

/** Copyright (C) 2010 Google Inc. All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are* met:**     * Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.*     * Redistributions in binary form must reproduce the above* copyright notice, this list of conditions and the following disclaimer* in the documentation and/or other materials provided with the* distribution.*     * Neither the name of Google Inc. nor the names of its* contributors may be used to endorse or promote products derived from* this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/// https://w3c.github.io/FileAPI/#blob-sectiontypedef (ArrayBuffer or ArrayBufferView or Blob or USVString) BlobPart;
[Exposed=(Window,Worker),Serializable
] interface Blob {[CallWith=ExecutionContext] constructor(optional sequence<BlobPart> blobParts, optional BlobPropertyBag options = {});readonly attribute unsigned long long size;readonly attribute DOMString type;// TODO(jsbell): start and end arguments should be [Clamp][RaisesException] Blob slice(optional long long start, optional long long end, optional DOMString contentType);[CallWith=ScriptState] ReadableStream stream();[CallWith=ScriptState] Promise<USVString> text();[CallWith=ScriptState] Promise<ArrayBuffer> arrayBuffer();
};

4、blob.idl接口定义实现类:

      third_party\blink\renderer\core\fileapi\blob.h

      third_party\blink\renderer\core\fileapi\blob.cc

/** Copyright (C) 2010 Google Inc. All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are* met:**     * Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.*     * Redistributions in binary form must reproduce the above* copyright notice, this list of conditions and the following disclaimer* in the documentation and/or other materials provided with the* distribution.*     * Neither the name of Google Inc. nor the names of its* contributors may be used to endorse or promote products derived from* this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_BLOB_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_BLOB_H_#include "base/memory/scoped_refptr.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/fileapi/url_registry.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"namespace blink {class BlobPropertyBag;
class ExceptionState;
class ExecutionContext;class CORE_EXPORT Blob : public ScriptWrappable,public URLRegistrable,public ImageBitmapSource {DEFINE_WRAPPERTYPEINFO();public:static Blob* Create(ExecutionContext*) {return MakeGarbageCollected<Blob>(BlobDataHandle::Create());}static Blob* Create(ExecutionContext* execution_context,const HeapVector<Member<V8BlobPart>>& blob_parts,const BlobPropertyBag* options);static Blob* Create(const unsigned char* data,size_t size,const String& content_type);explicit Blob(scoped_refptr<BlobDataHandle>);~Blob() override;virtual uint64_t size() const { return blob_data_handle_->size(); }Blob* slice(int64_t start,int64_t end,const String& content_type,ExceptionState&) const;// To allow ExceptionState to be passed in last, manually enumerate the// optional argument overloads.Blob* slice(ExceptionState& exception_state) const {return slice(0, std::numeric_limits<int64_t>::max(), String(),exception_state);}Blob* slice(int64_t start, ExceptionState& exception_state) const {return slice(start, std::numeric_limits<int64_t>::max(), String(),exception_state);}Blob* slice(int64_t start,int64_t end,ExceptionState& exception_state) const {return slice(start, end, String(), exception_state);}ReadableStream* stream(ScriptState* script_state) const;ScriptPromise text(ScriptState* script_state);ScriptPromise arrayBuffer(ScriptState* script_state);String type() const { return blob_data_handle_->GetType(); }String Uuid() const { return blob_data_handle_->Uuid(); }scoped_refptr<BlobDataHandle> GetBlobDataHandle() const {return blob_data_handle_;}// True for all File instances, including the user-built ones.virtual bool IsFile() const { return false; }// Only true for File instances that are backed by platform files.virtual bool HasBackingFile() const { return false; }// Used by the JavaScript Blob and File constructors.void AppendTo(BlobData&) const;// URLRegistrable to support PublicURLs.URLRegistry& Registry() const final;bool IsMojoBlob() final;void CloneMojoBlob(mojo::PendingReceiver<mojom::blink::Blob>) final;mojo::PendingRemote<mojom::blink::Blob> AsMojoBlob() const;// ImageBitmapSource implementationbool IsBlob() const override { return true; }protected:static void PopulateBlobData(BlobData* blob_data,const HeapVector<Member<V8BlobPart>>& parts,bool normalize_line_endings_to_native);static void ClampSliceOffsets(uint64_t size, int64_t& start, int64_t& end);// Called by the Blob and File constructors when processing the 'type'// option per the FileAPI standard. Returns "" if |type| contains any// character outside U+0020...U+007E, or |type| ASCII-lowercased otherwise.static String NormalizeType(const String& type);private:Blob() = delete;scoped_refptr<BlobDataHandle> blob_data_handle_;
};}  // namespace blink#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_BLOB_H_

三、c++测试用例堆栈图:

blink_core.dll!blink::LayoutTheme::DisplayNameForFile(const blink::File & file) 行 834
blink_core.dll!blink::FileInputType::FileStatusText() 行 578
blink_core.dll!blink::FileInputType::UpdateView() 行 587	
blink_core.dll!blink::FileInputType::SetFiles(blink::FileList * files) 行 422
blink_core.dll!blink::FileInputType::SetFilesAndDispatchEvents(blink::FileList * files) 行 426
blink_core.dll!blink::FileInputType::FilesChosen(WTF::Vector<mojo::StructPtr<blink::mojom::blink::FileChooserFileInfo>,0,WTF::PartitionAllocator> files, const base::FilePath & base_dir) 行 457	
blink_core.dll!blink::FileChooser::DidChooseFiles(mojo::StructPtr<blink::mojom::blink::FileChooserResult> result)

可以看到点击选择文件 ”账号.txt“,已经成功进入src\third_party\blink\renderer\core\fileapi\file.h

  const String& GetPath() const {
#if DCHECK_IS_ON()
    DCHECK(HasValidFilePath());
#endif
    return path_;
  }
  const String& name() const { return name_; }

两个函数断点。至此分析完毕。


http://www.mrgr.cn/news/44121.html

相关文章:

  • 怎么将mp4转换为mp3?教你6种值得收藏的视频转音频方法!
  • 走进异常类的世界,自定义业务异常类实现指南
  • 【机器学习】深度学习、强化学习和深度强化学习?
  • 个人网站,怎么操作才能提升个人网站的流量
  • PostgreSQL分区表,实战细节满满
  • 科普篇 --- 什么是汽车中的API?
  • DataX+Crontab实现多任务顺序定时同步
  • Hive数仓操作(七)
  • 鸿蒙开发(NEXT/API 12)【穿戴设备传感器获取】手机侧应用开发
  • Linux命令:用于管理 Linux 系统中用户组的命令行工具gpasswd详解
  • 【数据结构】【链表代码】随机链表的复制
  • C# 雷赛运动控制器 SMC304 新建工程
  • S7-200 SMART Modbus RTU常见问题
  • detectron2/data/catalog.py源码笔记
  • MATLAB图像去雾系统
  • Codeforces Rund 977 div2 个人题解(A~E1)
  • Redis基础
  • 深入理解Flask应用中不同模式下的数据库连接池
  • 构建 10 万卡 GPU 集群的技术挑战
  • MES系统在数字化转型中的重要性